2 % (c) The AQUA Project, Glasgow University, 1993-1998
4 \section[MachMisc]{Description of various machine-specific things}
7 #include "nativeGen/NCG.h"
15 volatileSaves, volatileRestores,
17 targetMaxDouble, targetMaxInt, targetMinDouble, targetMinInt,
23 Instr(..), IF_ARCH_i386(Operand(..) COMMA,)
26 IF_ARCH_i386(i386_insert_ffrees COMMA,)
34 RI(..), riZero, fpRelEA, moveSp, fPair
38 #include "HsVersions.h"
39 #include "../includes/config.h"
41 import AbsCSyn ( MagicId(..) )
42 import AbsCUtils ( magicIdPrimRep )
43 import CLabel ( CLabel, isAsmTemp )
44 import Literal ( mkMachInt, Literal(..) )
45 import MachRegs ( callerSaves,
46 get_MagicId_addr, get_MagicId_reg_or_addr,
47 Imm(..), Reg(..), MachRegsAddr(..)
48 # if sparc_TARGET_ARCH
52 import PrimRep ( PrimRep(..) )
53 import Stix ( StixStmt(..), StixExpr(..), StixReg(..),
54 CodeSegment, DestInfo(..) )
55 import Panic ( panic )
57 import Outputable ( pprPanic, ppr, showSDoc )
58 import IOExts ( trace )
59 import Config ( cLeadingUnderscore )
62 import Maybe ( catMaybes )
66 underscorePrefix :: Bool -- leading underscore on assembler labels?
67 underscorePrefix = (cLeadingUnderscore == "YES")
69 ---------------------------
70 fmtAsmLbl :: String -> String -- for formatting labels
74 {- The alpha assembler likes temporary labels to look like $L123
75 instead of L123. (Don't toss the L, because then Lf28
84 % ----------------------------------------------------------------
86 We (allegedly) put the first six C-call arguments in registers;
87 where do we start putting the rest of them?
89 eXTRA_STK_ARGS_HERE :: Int
91 = IF_ARCH_alpha(0, IF_ARCH_i386(23{-6x4bytes-}, IF_ARCH_sparc(23,???)))
94 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96 Now the volatile saves and restores. We add the basic guys to the
97 list of ``user'' registers provided. Note that there are more basic
98 registers on the restore list, because some are reloaded from
101 (@volatileRestores@ used only for wrapper-hungry PrimOps.)
104 volatileSaves, volatileRestores :: [MagicId] -> [StixStmt]
106 volatileSaves = volatileSavesOrRestores True
107 volatileRestores = volatileSavesOrRestores False
109 save_cands = [BaseReg,Sp,Su,SpLim,Hp,HpLim]
110 restore_cands = save_cands
112 volatileSavesOrRestores do_saves vols
113 = catMaybes (map mkCode vols)
116 | case mid of { BaseReg -> True; _ -> False }
117 = panic "volatileSavesOrRestores:BaseReg"
118 | not (callerSaves mid)
120 | otherwise -- must be callee-saves ...
121 = case get_MagicId_reg_or_addr mid of
122 -- If stored in BaseReg, we ain't interested
126 -- OK, it's callee-saves, and in a real reg (rrno).
127 -- We have to cook up some transfer code.
128 {- Note that the use of (StixMagicId mid) here is a bit subtle.
129 Here, we only create those for MagicIds which are stored in
130 a real reg on this arch -- the preceding case on the result
131 of get_MagicId_reg_or_addr guarantees this. Later, when
132 selecting insns, that means these assignments are sure to turn
133 into real reg-to-mem or mem-to-reg moves, rather than being
134 pointless moves from some address in the reg-table
137 -> Just (StAssignMem rep addr
138 (StReg (StixMagicId mid)))
140 -> Just (StAssignReg rep (StixMagicId mid)
143 rep = magicIdPrimRep mid
144 addr = get_MagicId_addr mid
147 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
149 Obviously slightly weedy
150 (Note that the floating point values aren't terribly important.)
153 targetMinDouble = MachDouble (-1.7976931348623157e+308)
154 targetMaxDouble = MachDouble (1.7976931348623157e+308)
155 targetMinInt = mkMachInt (-2147483648)
156 targetMaxInt = mkMachInt 2147483647
159 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161 This algorithm for determining the $\log_2$ of exact powers of 2 comes
162 from GCC. It requires bit manipulation primitives, and we use GHC
169 exactLog2 :: Integer -> Maybe Integer
171 = if (x <= 0 || x >= 2147483648) then
174 case iUnbox (fromInteger x) of { x# ->
175 if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
178 Just (toInteger (iBox (pow2 x#)))
181 pow2 x# | x# ==# 1# = 0#
182 | otherwise = 1# +# pow2 (w2i (i2w x# `shiftRL#` 1#))
185 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
189 #if alpha_TARGET_ARCH
190 = ALWAYS -- For BI (same as BR)
191 | EQQ -- For CMP and BI (NB: "EQ" is a 1.3 Prelude name)
193 | GTT -- For BI only (NB: "GT" is a 1.3 Prelude name)
194 | LE -- For CMP and BI
195 | LTT -- For CMP and BI (NB: "LT" is a 1.3 Prelude name)
197 | NEVER -- For BI (null instruction)
198 | ULE -- For CMP only
199 | ULT -- For CMP only
202 = ALWAYS -- What's really used? ToDo
218 #if sparc_TARGET_ARCH
219 = ALWAYS -- What's really used? ToDo
236 deriving Eq -- to make an assertion work
241 #if alpha_TARGET_ARCH
244 -- | W -- word (2 bytes): UNUSED
246 | L -- longword (4 bytes)
247 | Q -- quadword (8 bytes)
248 -- | FF -- VAX F-style floating pt: UNUSED
249 -- | GF -- VAX G-style floating pt: UNUSED
250 -- | DF -- VAX D-style floating pt: UNUSED
251 -- | SF -- IEEE single-precision floating pt: UNUSED
252 | TF -- IEEE double-precision floating pt
256 | Bu -- byte (unsigned)
258 | Wu -- word (unsigned)
259 | L -- longword (signed)
260 | Lu -- longword (unsigned)
261 | F -- IEEE single-precision floating pt
262 | DF -- IEEE single-precision floating pt
263 | F80 -- Intel 80-bit internal FP format; only used for spilling
265 #if sparc_TARGET_ARCH
267 | Bu -- byte (unsigned)
268 | H -- halfword (signed, 2 bytes)
269 | Hu -- halfword (unsigned, 2 bytes)
270 | W -- word (4 bytes)
271 | F -- IEEE single-precision floating pt
272 | DF -- IEEE single-precision floating pt
275 primRepToSize :: PrimRep -> Size
277 primRepToSize PtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
278 primRepToSize CodePtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
279 primRepToSize DataPtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
280 primRepToSize RetRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
281 primRepToSize CostCentreRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
282 primRepToSize CharRep = IF_ARCH_alpha(L, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
284 primRepToSize Int8Rep = IF_ARCH_alpha(B, IF_ARCH_i386(B, IF_ARCH_sparc(B, )))
285 primRepToSize Int16Rep = IF_ARCH_alpha(err,IF_ARCH_i386(W, IF_ARCH_sparc(H, )))
286 where err = primRepToSize_fail "Int16Rep"
287 primRepToSize Int32Rep = IF_ARCH_alpha(L, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
288 primRepToSize Word8Rep = IF_ARCH_alpha(Bu, IF_ARCH_i386(Bu, IF_ARCH_sparc(Bu, )))
289 primRepToSize Word16Rep = IF_ARCH_alpha(err,IF_ARCH_i386(Wu, IF_ARCH_sparc(Hu, )))
290 where err = primRepToSize_fail "Word16Rep"
291 primRepToSize Word32Rep = IF_ARCH_alpha(L, IF_ARCH_i386(Lu, IF_ARCH_sparc(W, )))
293 primRepToSize IntRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
294 primRepToSize WordRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
295 primRepToSize AddrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
296 primRepToSize FloatRep = IF_ARCH_alpha(TF, IF_ARCH_i386(F, IF_ARCH_sparc(F, )))
297 primRepToSize DoubleRep = IF_ARCH_alpha(TF, IF_ARCH_i386(DF, IF_ARCH_sparc(DF, )))
298 primRepToSize ArrayRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
299 primRepToSize ByteArrayRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
300 primRepToSize PrimPtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
301 primRepToSize WeakPtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
302 primRepToSize ForeignObjRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
303 primRepToSize BCORep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
304 primRepToSize StablePtrRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
305 primRepToSize StableNameRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
306 primRepToSize ThreadIdRep = IF_ARCH_alpha(Q, IF_ARCH_i386(L, IF_ARCH_sparc(W, )))
308 primRepToSize Word64Rep = primRepToSize_fail "Word64Rep"
309 primRepToSize Int64Rep = primRepToSize_fail "Int64Rep"
310 primRepToSize other = primRepToSize_fail (showSDoc (ppr other))
312 primRepToSize_fail str
313 = error ("ERROR: MachMisc.primRepToSize: cannot handle `" ++ str ++ "'.\n\t"
314 ++ "Workaround: use -fvia-C.\n\t"
315 ++ "Perhaps you should report it as a GHC bug,\n\t"
316 ++ "to glasgow-haskell-bugs@haskell.org.")
320 %************************************************************************
322 \subsection{Machine's assembly language}
324 %************************************************************************
326 We have a few common ``instructions'' (nearly all the pseudo-ops) but
327 mostly all of @Instr@ is machine-specific.
331 = COMMENT FAST_STRING -- comment pseudo-op
332 | SEGMENT CodeSegment -- {data,text} segment pseudo-op
333 | LABEL CLabel -- global label pseudo-op
334 | ASCII Bool -- True <=> needs backslash conversion
335 String -- the literal string
338 | DELTA Int -- specify current stack offset for
339 -- benefit of subsequent passes
343 #if alpha_TARGET_ARCH
345 -- data Instr continues...
349 | LD Size Reg MachRegsAddr -- size, dst, src
350 | LDA Reg MachRegsAddr -- dst, src
351 | LDAH Reg MachRegsAddr -- dst, src
352 | LDGP Reg MachRegsAddr -- dst, src
353 | LDI Size Reg Imm -- size, dst, src
354 | ST Size Reg MachRegsAddr -- size, src, dst
359 | ABS Size RI Reg -- size, src, dst
360 | NEG Size Bool RI Reg -- size, overflow, src, dst
361 | ADD Size Bool Reg RI Reg -- size, overflow, src, src, dst
362 | SADD Size Size Reg RI Reg -- size, scale, src, src, dst
363 | SUB Size Bool Reg RI Reg -- size, overflow, src, src, dst
364 | SSUB Size Size Reg RI Reg -- size, scale, src, src, dst
365 | MUL Size Bool Reg RI Reg -- size, overflow, src, src, dst
366 | DIV Size Bool Reg RI Reg -- size, unsigned, src, src, dst
367 | REM Size Bool Reg RI Reg -- size, unsigned, src, src, dst
369 -- Simple bit-twiddling.
389 | CMP Cond Reg RI Reg
396 | FADD Size Reg Reg Reg
397 | FDIV Size Reg Reg Reg
398 | FMUL Size Reg Reg Reg
399 | FSUB Size Reg Reg Reg
400 | CVTxy Size Size Reg Reg
401 | FCMP Size Cond Reg Reg Reg
409 | JMP Reg MachRegsAddr Int
411 | JSR Reg MachRegsAddr Int
413 -- Alpha-specific pseudo-ops.
422 #endif {- alpha_TARGET_ARCH -}
425 Intel, in their infinite wisdom, selected a stack model for floating
426 point registers on x86. That might have made sense back in 1979 --
427 nowadays we can see it for the nonsense it really is. A stack model
428 fits poorly with the existing nativeGen infrastructure, which assumes
429 flat integer and FP register sets. Prior to this commit, nativeGen
430 could not generate correct x86 FP code -- to do so would have meant
431 somehow working the register-stack paradigm into the register
432 allocator and spiller, which sounds very difficult.
434 We have decided to cheat, and go for a simple fix which requires no
435 infrastructure modifications, at the expense of generating ropey but
436 correct FP code. All notions of the x86 FP stack and its insns have
437 been removed. Instead, we pretend (to the instruction selector and
438 register allocator) that x86 has six floating point registers, %fake0
439 .. %fake5, which can be used in the usual flat manner. We further
440 claim that x86 has floating point instructions very similar to SPARC
441 and Alpha, that is, a simple 3-operand register-register arrangement.
442 Code generation and register allocation proceed on this basis.
444 When we come to print out the final assembly, our convenient fiction
445 is converted to dismal reality. Each fake instruction is
446 independently converted to a series of real x86 instructions.
447 %fake0 .. %fake5 are mapped to %st(0) .. %st(5). To do reg-reg
448 arithmetic operations, the two operands are pushed onto the top of the
449 FP stack, the operation done, and the result copied back into the
450 relevant register. There are only six %fake registers because 2 are
451 needed for the translation, and x86 has 8 in total.
453 The translation is inefficient but is simple and it works. A cleverer
454 translation would handle a sequence of insns, simulating the FP stack
455 contents, would not impose a fixed mapping from %fake to %st regs, and
456 hopefully could avoid most of the redundant reg-reg moves of the
459 We might as well make use of whatever unique FP facilities Intel have
460 chosen to bless us with (let's not be churlish, after all).
461 Hence GLDZ and GLD1. Bwahahahahahahaha!
463 LATER (10 Nov 2000): idiv gives problems with the register spiller,
464 because the spiller is simpleminded and because idiv has fixed uses of
465 %eax and %edx. Rather than make the spiller cleverer, we do away with
466 idiv, and instead have iquot and irem fake (integer) insns, which have
467 no operand register constraints -- ie, they behave like add, sub, mul.
468 The printer-outer transforms them to a sequence of real insns which does
469 the Right Thing (tm). As with the FP stuff, this gives ropey code,
470 but we don't care, since it doesn't get used much. We hope.
475 -- data Instr continues...
479 | MOV Size Operand Operand
480 | MOVZxL Size Operand Operand -- size is the size of operand 1
481 | MOVSxL Size Operand Operand -- size is the size of operand 1
483 -- Load effective address (also a very useful three-operand add instruction :-)
485 | LEA Size Operand Operand
489 | ADD Size Operand Operand
490 | SUB Size Operand Operand
491 | IMUL Size Operand Operand -- signed int mul
492 | MUL Size Operand Operand -- unsigned int mul
493 | IMUL64 Reg Reg -- 32 x 32 -> 64 signed mul
494 -- operand1:operand2 := (operand1[31:0] *signed operand2[31:0])
496 -- Quotient and remainder. SEE comment above -- these are not
497 -- real x86 insns; instead they are expanded when printed
498 -- into a sequence of real insns.
500 | IQUOT Size Operand Operand -- signed quotient
501 | IREM Size Operand Operand -- signed remainder
502 | QUOT Size Operand Operand -- unsigned quotient
503 | REM Size Operand Operand -- unsigned remainder
505 -- Simple bit-twiddling.
507 | AND Size Operand Operand
508 | OR Size Operand Operand
509 | XOR Size Operand Operand
511 | NEGI Size Operand -- NEG instruction (name clash with Cond)
512 | SHL Size Imm Operand -- Only immediate shifts allowed
513 | SAR Size Imm Operand -- Only immediate shifts allowed
514 | SHR Size Imm Operand -- Only immediate shifts allowed
515 | BT Size Imm Operand
520 -- Note that we cheat by treating G{ABS,MOV,NEG} of doubles
521 -- as single instructions right up until we spit them out.
523 -- all the 3-operand fake fp insns are src1 src2 dst
524 -- and furthermore are constrained to be fp regs only.
525 -- IMPORTANT: keep is_G_insn up to date with any changes here
526 | GMOV Reg Reg -- src(fpreg), dst(fpreg)
527 | GLD Size MachRegsAddr Reg -- src, dst(fpreg)
528 | GST Size Reg MachRegsAddr -- src(fpreg), dst
530 | GLDZ Reg -- dst(fpreg)
531 | GLD1 Reg -- dst(fpreg)
533 | GFTOI Reg Reg -- src(fpreg), dst(intreg)
534 | GDTOI Reg Reg -- src(fpreg), dst(intreg)
536 | GITOF Reg Reg -- src(intreg), dst(fpreg)
537 | GITOD Reg Reg -- src(intreg), dst(fpreg)
539 | GADD Size Reg Reg Reg -- src1, src2, dst
540 | GDIV Size Reg Reg Reg -- src1, src2, dst
541 | GSUB Size Reg Reg Reg -- src1, src2, dst
542 | GMUL Size Reg Reg Reg -- src1, src2, dst
544 -- FP compare. Cond must be `elem` [EQQ, NE, LE, LTT, GE, GTT]
545 -- Compare src1 with src2; set the Zero flag iff the numbers are
546 -- comparable and the comparison is True. Subsequent code must
547 -- test the %eflags zero flag regardless of the supplied Cond.
548 | GCMP Cond Reg Reg -- src1, src2
550 | GABS Size Reg Reg -- src, dst
551 | GNEG Size Reg Reg -- src, dst
552 | GSQRT Size Reg Reg -- src, dst
553 | GSIN Size Reg Reg -- src, dst
554 | GCOS Size Reg Reg -- src, dst
555 | GTAN Size Reg Reg -- src, dst
557 | GFREE -- do ffree on all x86 regs; an ugly hack
560 | TEST Size Operand Operand
561 | CMP Size Operand Operand
573 | JMP DestInfo Operand -- possible dests, target
574 | JXX Cond CLabel -- target
579 | CLTD -- sign extend %eax into %edx:%eax
582 = OpReg Reg -- register
583 | OpImm Imm -- immediate value
584 | OpAddr MachRegsAddr -- memory reference
587 i386_insert_ffrees :: [Instr] -> [Instr]
588 i386_insert_ffrees insns
589 | any is_G_instr insns
590 = concatMap ffree_before_nonlocal_transfers insns
594 ffree_before_nonlocal_transfers insn
596 CALL _ -> [GFREE, insn]
597 -- Jumps to immediate labels are local
598 JMP _ (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> [insn]
599 -- If a jump mentions dests, it is a local jump thru
601 JMP (DestInfo _) _ -> [insn]
602 JMP _ _ -> [GFREE, insn]
606 -- if you ever add a new FP insn to the fake x86 FP insn set,
607 -- you must update this too
608 is_G_instr :: Instr -> Bool
611 GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True;
612 GLDZ _ -> True; GLD1 _ -> True;
613 GFTOI _ _ -> True; GDTOI _ _ -> True;
614 GITOF _ _ -> True; GITOD _ _ -> True;
615 GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True
616 GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
617 GCMP _ _ _ -> True; GABS _ _ _ -> True
618 GNEG _ _ _ -> True; GSQRT _ _ _ -> True
619 GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True;
620 GFREE -> panic "is_G_instr: GFREE (!)"
623 #endif {- i386_TARGET_ARCH -}
627 #if sparc_TARGET_ARCH
629 -- data Instr continues...
633 | LD Size MachRegsAddr Reg -- size, src, dst
634 | ST Size Reg MachRegsAddr -- size, src, dst
638 | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
639 | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
640 | UMUL Bool Reg RI Reg -- cc?, src1, src2, dst
641 | SMUL Bool Reg RI Reg -- cc?, src1, src2, dst
642 | RDY Reg -- move contents of Y register to reg
644 -- Simple bit-twiddling.
646 | AND Bool Reg RI Reg -- cc?, src1, src2, dst
647 | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
648 | OR Bool Reg RI Reg -- cc?, src1, src2, dst
649 | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
650 | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
651 | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
652 | SLL Reg RI Reg -- src1, src2, dst
653 | SRL Reg RI Reg -- src1, src2, dst
654 | SRA Reg RI Reg -- src1, src2, dst
655 | SETHI Imm Reg -- src, dst
656 | NOP -- Really SETHI 0, %g0, but worth an alias
660 -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
661 -- right up until we spit them out.
663 | FABS Size Reg Reg -- src dst
664 | FADD Size Reg Reg Reg -- src1, src2, dst
665 | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
666 | FDIV Size Reg Reg Reg -- src1, src2, dst
667 | FMOV Size Reg Reg -- src, dst
668 | FMUL Size Reg Reg Reg -- src1, src2, dst
669 | FNEG Size Reg Reg -- src, dst
670 | FSQRT Size Reg Reg -- src, dst
671 | FSUB Size Reg Reg Reg -- src1, src2, dst
672 | FxTOy Size Size Reg Reg -- src, dst
676 | BI Cond Bool Imm -- cond, annul?, target
677 | BF Cond Bool Imm -- cond, annul?, target
679 | JMP DestInfo MachRegsAddr -- target
680 | CALL Imm Int Bool -- target, args, terminal
687 riZero (RIImm (ImmInt 0)) = True
688 riZero (RIImm (ImmInteger 0)) = True
689 riZero (RIReg (RealReg 0)) = True
692 -- Calculate the effective address which would be used by the
693 -- corresponding fpRel sequence. fpRel is in MachRegs.lhs,
694 -- alas -- can't have fpRelEA here because of module dependencies.
695 fpRelEA :: Int -> Reg -> Instr
697 = ADD False False fp (RIImm (ImmInt (n * BYTES_PER_WORD))) dst
699 -- Code to shift the stack pointer by n words.
700 moveSp :: Int -> Instr
702 = ADD False False sp (RIImm (ImmInt (n * BYTES_PER_WORD))) sp
704 -- Produce the second-half-of-a-double register given the first half.
706 fPair (RealReg n) | n >= 32 && n `mod` 2 == 0 = RealReg (n+1)
707 fPair other = pprPanic "fPair(sparc NCG)" (ppr other)
708 #endif {- sparc_TARGET_ARCH -}