2 % (c) The AQUA Project, Glasgow University, 1996-1998
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 module MachCode ( stmtsToInstrs, InstrBlock ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import Unique ( Unique )
18 import MachMisc -- may differ per-platform
20 import OrdList ( OrdList, nilOL, isNilOL, unitOL, appOL, toOL,
21 snocOL, consOL, concatOL )
22 import MachOp ( MachOp(..), pprMachOp )
23 import AbsCUtils ( magicIdPrimRep )
24 import PprAbsC ( pprMagicId )
25 import ForeignCall ( CCallConv(..) )
26 import CLabel ( CLabel, labelDynamic )
27 #if sparc_TARGET_ARCH || alpha_TARGET_ARCH
28 import CLabel ( isAsmTemp )
30 import Maybes ( maybeToBool )
31 import PrimRep ( isFloatingRep, is64BitRep, PrimRep(..),
32 getPrimRepArrayElemSize )
33 import Stix ( getNatLabelNCG, StixStmt(..), StixExpr(..),
34 StixReg(..), pprStixReg, StixVReg(..), CodeSegment(..),
35 DestInfo, hasDestInfo,
36 pprStixExpr, repOfStixExpr,
38 NatM, thenNat, returnNat, mapNat,
39 mapAndUnzipNat, mapAccumLNat,
40 getDeltaNat, setDeltaNat, getUniqueNat,
45 import Outputable ( panic, pprPanic, showSDoc )
46 import qualified Outputable
47 import CmdLineOpts ( opt_Static )
48 import Stix ( pprStixStmt )
51 import IOExts ( trace )
56 @InstrBlock@s are the insn sequences generated by the insn selectors.
57 They are really trees of insns to facilitate fast appending, where a
58 left-to-right traversal (pre-order?) yields the insns in the correct
62 type InstrBlock = OrdList Instr
67 Code extractor for an entire stix tree---stix statement level.
70 stmtsToInstrs :: [StixStmt] -> NatM InstrBlock
72 = mapNat stmtToInstrs stmts `thenNat` \ instrss ->
73 returnNat (concatOL instrss)
76 stmtToInstrs :: StixStmt -> NatM InstrBlock
77 stmtToInstrs stmt = case stmt of
78 StComment s -> returnNat (unitOL (COMMENT s))
79 StSegment seg -> returnNat (unitOL (SEGMENT seg))
81 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
83 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
86 StLabel lab -> returnNat (unitOL (LABEL lab))
88 StJump dsts arg -> genJump dsts (derefDLL arg)
89 StCondJump lab arg -> genCondJump lab (derefDLL arg)
91 -- A call returning void, ie one done for its side-effects. Note
92 -- that this is the only StVoidable we handle.
93 StVoidable (StCall fn cconv VoidRep args)
94 -> genCCall fn cconv VoidRep (map derefDLL args)
96 StAssignMem pk addr src
97 | isFloatingRep pk -> assignMem_FltCode pk (derefDLL addr) (derefDLL src)
99 && is64BitRep pk -> assignMem_I64Code (derefDLL addr) (derefDLL src)
100 | otherwise -> assignMem_IntCode pk (derefDLL addr) (derefDLL src)
101 StAssignReg pk reg src
102 | isFloatingRep pk -> assignReg_FltCode pk reg (derefDLL src)
103 | ncg_target_is_32bit
104 && is64BitRep pk -> assignReg_I64Code reg (derefDLL src)
105 | otherwise -> assignReg_IntCode pk reg (derefDLL src)
108 -- When falling through on the Alpha, we still have to load pv
109 -- with the address of the next routine, so that it can load gp.
110 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
114 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
115 returnNat (DATA (primRepToSize kind) imms
116 `consOL` concatOL codes)
118 getData :: StixExpr -> NatM (InstrBlock, Imm)
119 getData (StInt i) = returnNat (nilOL, ImmInteger i)
120 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
121 getData (StFloat d) = returnNat (nilOL, ImmFloat d)
122 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
123 getData (StString s) = panic "MachCode.stmtToInstrs: unlifted StString"
124 -- the linker can handle simple arithmetic...
125 getData (StIndex rep (StCLbl lbl) (StInt off)) =
127 ImmIndex lbl (fromInteger off * getPrimRepArrayElemSize rep))
129 -- Top-level lifted-out string. The segment will already have been set
130 -- (see Stix.liftStrings).
132 -> returnNat (unitOL (ASCII True (_UNPK_ str)))
135 other -> pprPanic "stmtToInstrs" (pprStixStmt other)
138 -- Walk a Stix tree, and insert dereferences to CLabels which are marked
139 -- as labelDynamic. stmt2Instrs calls derefDLL selectively, because
140 -- not all such CLabel occurrences need this dereferencing -- SRTs don't
142 derefDLL :: StixExpr -> StixExpr
144 | opt_Static -- short out the entire deal if not doing DLLs
151 StCLbl lbl -> if labelDynamic lbl
152 then StInd PtrRep (StCLbl lbl)
154 -- all the rest are boring
155 StIndex pk base offset -> StIndex pk (qq base) (qq offset)
156 StMachOp mop args -> StMachOp mop (map qq args)
157 StInd pk addr -> StInd pk (qq addr)
158 StCall who cc pk args -> StCall who cc pk (map qq args)
164 _ -> pprPanic "derefDLL: unhandled case"
168 %************************************************************************
170 \subsection{General things for putting together code sequences}
172 %************************************************************************
175 mangleIndexTree :: StixExpr -> StixExpr
177 mangleIndexTree (StIndex pk base (StInt i))
178 = StMachOp MO_Nat_Add [base, off]
180 off = StInt (i * toInteger (getPrimRepArrayElemSize pk))
182 mangleIndexTree (StIndex pk base off)
183 = StMachOp MO_Nat_Add [
186 in if s == 0 then off
187 else StMachOp MO_Nat_Shl [off, StInt (toInteger s)]
190 shift :: PrimRep -> Int
191 shift rep = case getPrimRepArrayElemSize rep of
196 other -> pprPanic "MachCode.mangleIndexTree.shift: unhandled rep size"
197 (Outputable.int other)
201 maybeImm :: StixExpr -> Maybe Imm
205 maybeImm (StIndex rep (StCLbl l) (StInt off))
206 = Just (ImmIndex l (fromInteger off * getPrimRepArrayElemSize rep))
208 | i >= toInteger (minBound::Int) && i <= toInteger (maxBound::Int)
209 = Just (ImmInt (fromInteger i))
211 = Just (ImmInteger i)
216 %************************************************************************
218 \subsection{The @Register64@ type}
220 %************************************************************************
222 Simple support for generating 64-bit code (ie, 64 bit values and 64
223 bit assignments) on 32-bit platforms. Unlike the main code generator
224 we merely shoot for generating working code as simply as possible, and
225 pay little attention to code quality. Specifically, there is no
226 attempt to deal cleverly with the fixed-vs-floating register
227 distinction; all values are generated into (pairs of) floating
228 registers, even if this would mean some redundant reg-reg moves as a
229 result. Only one of the VRegUniques is returned, since it will be
230 of the VRegUniqueLo form, and the upper-half VReg can be determined
231 by applying getHiVRegFromLo to it.
235 data ChildCode64 -- a.k.a "Register64"
238 VRegUnique -- unique for the lower 32-bit temporary
239 -- which contains the result; use getHiVRegFromLo to find
240 -- the other VRegUnique.
241 -- Rules of this simplified insn selection game are
242 -- therefore that the returned VRegUnique may be modified
244 assignMem_I64Code :: StixExpr -> StixExpr -> NatM InstrBlock
245 assignReg_I64Code :: StixReg -> StixExpr -> NatM InstrBlock
246 iselExpr64 :: StixExpr -> NatM ChildCode64
248 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
252 assignMem_I64Code addrTree valueTree
253 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
254 getRegister addrTree `thenNat` \ register_addr ->
255 getNewRegNCG IntRep `thenNat` \ t_addr ->
256 let rlo = VirtualRegI vrlo
257 rhi = getHiVRegFromLo rlo
258 code_addr = registerCode register_addr t_addr
259 reg_addr = registerName register_addr t_addr
260 -- Little-endian store
261 mov_lo = MOV L (OpReg rlo)
262 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
263 mov_hi = MOV L (OpReg rhi)
264 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
266 returnNat (vcode `appOL` code_addr `snocOL` mov_lo `snocOL` mov_hi)
268 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
269 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
271 r_dst_lo = mkVReg u_dst IntRep
272 r_src_lo = VirtualRegI vr_src_lo
273 r_dst_hi = getHiVRegFromLo r_dst_lo
274 r_src_hi = getHiVRegFromLo r_src_lo
275 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
276 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
279 vcode `snocOL` mov_lo `snocOL` mov_hi
282 assignReg_I64Code lvalue valueTree
283 = pprPanic "assignReg_I64Code(i386): invalid lvalue"
288 iselExpr64 (StInd pk addrTree)
290 = getRegister addrTree `thenNat` \ register_addr ->
291 getNewRegNCG IntRep `thenNat` \ t_addr ->
292 getNewRegNCG IntRep `thenNat` \ rlo ->
293 let rhi = getHiVRegFromLo rlo
294 code_addr = registerCode register_addr t_addr
295 reg_addr = registerName register_addr t_addr
296 mov_lo = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
298 mov_hi = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
302 ChildCode64 (code_addr `snocOL` mov_lo `snocOL` mov_hi)
306 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
308 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
309 let r_dst_hi = getHiVRegFromLo r_dst_lo
310 r_src_lo = mkVReg vu IntRep
311 r_src_hi = getHiVRegFromLo r_src_lo
312 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
313 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
316 ChildCode64 (toOL [mov_lo, mov_hi]) (getVRegUnique r_dst_lo)
319 iselExpr64 (StCall fn cconv kind args)
321 = genCCall fn cconv kind args `thenNat` \ call ->
322 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
323 let r_dst_hi = getHiVRegFromLo r_dst_lo
324 mov_lo = MOV L (OpReg eax) (OpReg r_dst_lo)
325 mov_hi = MOV L (OpReg edx) (OpReg r_dst_hi)
328 ChildCode64 (call `snocOL` mov_lo `snocOL` mov_hi)
329 (getVRegUnique r_dst_lo)
333 = pprPanic "iselExpr64(i386)" (pprStixExpr expr)
335 #endif {- i386_TARGET_ARCH -}
337 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339 #if sparc_TARGET_ARCH
341 assignMem_I64Code addrTree valueTree
342 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
343 getRegister addrTree `thenNat` \ register_addr ->
344 getNewRegNCG IntRep `thenNat` \ t_addr ->
345 let rlo = VirtualRegI vrlo
346 rhi = getHiVRegFromLo rlo
347 code_addr = registerCode register_addr t_addr
348 reg_addr = registerName register_addr t_addr
350 mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
351 mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
353 returnNat (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
356 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
357 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
359 r_dst_lo = mkVReg u_dst IntRep
360 r_src_lo = VirtualRegI vr_src_lo
361 r_dst_hi = getHiVRegFromLo r_dst_lo
362 r_src_hi = getHiVRegFromLo r_src_lo
363 mov_lo = mkMOV r_src_lo r_dst_lo
364 mov_hi = mkMOV r_src_hi r_dst_hi
365 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
368 vcode `snocOL` mov_hi `snocOL` mov_lo
370 assignReg_I64Code lvalue valueTree
371 = pprPanic "assignReg_I64Code(sparc): invalid lvalue"
375 -- Don't delete this -- it's very handy for debugging.
377 -- | trace ("iselExpr64: " ++ showSDoc (pprStixExpr expr)) False
378 -- = panic "iselExpr64(???)"
380 iselExpr64 (StInd pk addrTree)
382 = getRegister addrTree `thenNat` \ register_addr ->
383 getNewRegNCG IntRep `thenNat` \ t_addr ->
384 getNewRegNCG IntRep `thenNat` \ rlo ->
385 let rhi = getHiVRegFromLo rlo
386 code_addr = registerCode register_addr t_addr
387 reg_addr = registerName register_addr t_addr
388 mov_hi = LD W (AddrRegImm reg_addr (ImmInt 0)) rhi
389 mov_lo = LD W (AddrRegImm reg_addr (ImmInt 4)) rlo
392 ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo)
396 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
398 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
399 let r_dst_hi = getHiVRegFromLo r_dst_lo
400 r_src_lo = mkVReg vu IntRep
401 r_src_hi = getHiVRegFromLo r_src_lo
402 mov_lo = mkMOV r_src_lo r_dst_lo
403 mov_hi = mkMOV r_src_hi r_dst_hi
404 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
407 ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
410 iselExpr64 (StCall fn cconv kind args)
412 = genCCall fn cconv kind args `thenNat` \ call ->
413 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
414 let r_dst_hi = getHiVRegFromLo r_dst_lo
415 mov_lo = mkMOV o0 r_dst_lo
416 mov_hi = mkMOV o1 r_dst_hi
417 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
420 ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo)
421 (getVRegUnique r_dst_lo)
425 = pprPanic "iselExpr64(sparc)" (pprStixExpr expr)
427 #endif {- sparc_TARGET_ARCH -}
429 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
433 %************************************************************************
435 \subsection{The @Register@ type}
437 %************************************************************************
439 @Register@s passed up the tree. If the stix code forces the register
440 to live in a pre-decided machine register, it comes out as @Fixed@;
441 otherwise, it comes out as @Any@, and the parent can decide which
442 register to put it in.
446 = Fixed PrimRep Reg InstrBlock
447 | Any PrimRep (Reg -> InstrBlock)
449 registerCode :: Register -> Reg -> InstrBlock
450 registerCode (Fixed _ _ code) reg = code
451 registerCode (Any _ code) reg = code reg
453 registerCodeF (Fixed _ _ code) = code
454 registerCodeF (Any _ _) = panic "registerCodeF"
456 registerCodeA (Any _ code) = code
457 registerCodeA (Fixed _ _ _) = panic "registerCodeA"
459 registerName :: Register -> Reg -> Reg
460 registerName (Fixed _ reg _) _ = reg
461 registerName (Any _ _) reg = reg
463 registerNameF (Fixed _ reg _) = reg
464 registerNameF (Any _ _) = panic "registerNameF"
466 registerRep :: Register -> PrimRep
467 registerRep (Fixed pk _ _) = pk
468 registerRep (Any pk _) = pk
470 swizzleRegisterRep :: Register -> PrimRep -> Register
471 swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
472 swizzleRegisterRep (Any _ codefn) rep = Any rep codefn
474 {-# INLINE registerCode #-}
475 {-# INLINE registerCodeF #-}
476 {-# INLINE registerName #-}
477 {-# INLINE registerNameF #-}
478 {-# INLINE registerRep #-}
479 {-# INLINE isFixed #-}
482 isFixed, isAny :: Register -> Bool
483 isFixed (Fixed _ _ _) = True
484 isFixed (Any _ _) = False
486 isAny = not . isFixed
489 Generate code to get a subtree into a @Register@:
492 getRegisterReg :: StixReg -> NatM Register
493 getRegister :: StixExpr -> NatM Register
496 getRegisterReg (StixMagicId mid)
497 = case get_MagicId_reg_or_addr mid of
499 -> let pk = magicIdPrimRep mid
500 in returnNat (Fixed pk (RealReg rrno) nilOL)
502 -- By this stage, the only MagicIds remaining should be the
503 -- ones which map to a real machine register on this platform. Hence ...
504 -> pprPanic "getRegisterReg-memory" (pprMagicId mid)
506 getRegisterReg (StixTemp (StixVReg u pk))
507 = returnNat (Fixed pk (mkVReg u pk) nilOL)
511 -- Don't delete this -- it's very handy for debugging.
513 -- | trace ("getRegiste: " ++ showSDoc (pprStixExpr expr)) False
514 -- = panic "getRegister(???)"
516 getRegister (StReg reg)
519 getRegister tree@(StIndex _ _ _)
520 = getRegister (mangleIndexTree tree)
522 getRegister (StCall fn cconv kind args)
523 | not (ncg_target_is_32bit && is64BitRep kind)
524 = genCCall fn cconv kind args `thenNat` \ call ->
525 returnNat (Fixed kind reg call)
527 reg = if isFloatingRep kind
528 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
529 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
531 getRegister (StString s)
532 = getNatLabelNCG `thenNat` \ lbl ->
534 imm_lbl = ImmCLbl lbl
537 SEGMENT RoDataSegment,
539 ASCII True (_UNPK_ s),
541 #if alpha_TARGET_ARCH
542 LDA dst (AddrImm imm_lbl)
545 MOV L (OpImm imm_lbl) (OpReg dst)
547 #if sparc_TARGET_ARCH
548 SETHI (HI imm_lbl) dst,
549 OR False dst (RIImm (LO imm_lbl)) dst
553 returnNat (Any PtrRep code)
555 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
556 -- end of machine-"independent" bit; here we go on the rest...
558 #if alpha_TARGET_ARCH
560 getRegister (StDouble d)
561 = getNatLabelNCG `thenNat` \ lbl ->
562 getNewRegNCG PtrRep `thenNat` \ tmp ->
563 let code dst = mkSeqInstrs [
566 DATA TF [ImmLab (rational d)],
568 LDA tmp (AddrImm (ImmCLbl lbl)),
569 LD TF dst (AddrReg tmp)]
571 returnNat (Any DoubleRep code)
573 getRegister (StPrim primop [x]) -- unary PrimOps
575 IntNegOp -> trivialUCode (NEG Q False) x
577 NotOp -> trivialUCode NOT x
579 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
580 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
582 OrdOp -> coerceIntCode IntRep x
585 Float2IntOp -> coerceFP2Int x
586 Int2FloatOp -> coerceInt2FP pr x
587 Double2IntOp -> coerceFP2Int x
588 Int2DoubleOp -> coerceInt2FP pr x
590 Double2FloatOp -> coerceFltCode x
591 Float2DoubleOp -> coerceFltCode x
593 other_op -> getRegister (StCall fn CCallConv DoubleRep [x])
595 fn = case other_op of
596 FloatExpOp -> SLIT("exp")
597 FloatLogOp -> SLIT("log")
598 FloatSqrtOp -> SLIT("sqrt")
599 FloatSinOp -> SLIT("sin")
600 FloatCosOp -> SLIT("cos")
601 FloatTanOp -> SLIT("tan")
602 FloatAsinOp -> SLIT("asin")
603 FloatAcosOp -> SLIT("acos")
604 FloatAtanOp -> SLIT("atan")
605 FloatSinhOp -> SLIT("sinh")
606 FloatCoshOp -> SLIT("cosh")
607 FloatTanhOp -> SLIT("tanh")
608 DoubleExpOp -> SLIT("exp")
609 DoubleLogOp -> SLIT("log")
610 DoubleSqrtOp -> SLIT("sqrt")
611 DoubleSinOp -> SLIT("sin")
612 DoubleCosOp -> SLIT("cos")
613 DoubleTanOp -> SLIT("tan")
614 DoubleAsinOp -> SLIT("asin")
615 DoubleAcosOp -> SLIT("acos")
616 DoubleAtanOp -> SLIT("atan")
617 DoubleSinhOp -> SLIT("sinh")
618 DoubleCoshOp -> SLIT("cosh")
619 DoubleTanhOp -> SLIT("tanh")
621 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
623 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
625 CharGtOp -> trivialCode (CMP LTT) y x
626 CharGeOp -> trivialCode (CMP LE) y x
627 CharEqOp -> trivialCode (CMP EQQ) x y
628 CharNeOp -> int_NE_code x y
629 CharLtOp -> trivialCode (CMP LTT) x y
630 CharLeOp -> trivialCode (CMP LE) x y
632 IntGtOp -> trivialCode (CMP LTT) y x
633 IntGeOp -> trivialCode (CMP LE) y x
634 IntEqOp -> trivialCode (CMP EQQ) x y
635 IntNeOp -> int_NE_code x y
636 IntLtOp -> trivialCode (CMP LTT) x y
637 IntLeOp -> trivialCode (CMP LE) x y
639 WordGtOp -> trivialCode (CMP ULT) y x
640 WordGeOp -> trivialCode (CMP ULE) x y
641 WordEqOp -> trivialCode (CMP EQQ) x y
642 WordNeOp -> int_NE_code x y
643 WordLtOp -> trivialCode (CMP ULT) x y
644 WordLeOp -> trivialCode (CMP ULE) x y
646 AddrGtOp -> trivialCode (CMP ULT) y x
647 AddrGeOp -> trivialCode (CMP ULE) y x
648 AddrEqOp -> trivialCode (CMP EQQ) x y
649 AddrNeOp -> int_NE_code x y
650 AddrLtOp -> trivialCode (CMP ULT) x y
651 AddrLeOp -> trivialCode (CMP ULE) x y
653 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
654 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
655 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
656 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
657 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
658 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
660 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
661 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
662 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
663 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
664 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
665 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
667 IntAddOp -> trivialCode (ADD Q False) x y
668 IntSubOp -> trivialCode (SUB Q False) x y
669 IntMulOp -> trivialCode (MUL Q False) x y
670 IntQuotOp -> trivialCode (DIV Q False) x y
671 IntRemOp -> trivialCode (REM Q False) x y
673 WordAddOp -> trivialCode (ADD Q False) x y
674 WordSubOp -> trivialCode (SUB Q False) x y
675 WordMulOp -> trivialCode (MUL Q False) x y
676 WordQuotOp -> trivialCode (DIV Q True) x y
677 WordRemOp -> trivialCode (REM Q True) x y
679 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
680 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
681 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
682 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
684 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
685 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
686 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
687 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
689 AddrAddOp -> trivialCode (ADD Q False) x y
690 AddrSubOp -> trivialCode (SUB Q False) x y
691 AddrRemOp -> trivialCode (REM Q True) x y
693 AndOp -> trivialCode AND x y
694 OrOp -> trivialCode OR x y
695 XorOp -> trivialCode XOR x y
696 SllOp -> trivialCode SLL x y
697 SrlOp -> trivialCode SRL x y
699 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
700 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
701 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
703 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
704 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
706 {- ------------------------------------------------------------
707 Some bizarre special code for getting condition codes into
708 registers. Integer non-equality is a test for equality
709 followed by an XOR with 1. (Integer comparisons always set
710 the result register to 0 or 1.) Floating point comparisons of
711 any kind leave the result in a floating point register, so we
712 need to wrangle an integer register out of things.
714 int_NE_code :: StixTree -> StixTree -> NatM Register
717 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
718 getNewRegNCG IntRep `thenNat` \ tmp ->
720 code = registerCode register tmp
721 src = registerName register tmp
722 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
724 returnNat (Any IntRep code__2)
726 {- ------------------------------------------------------------
727 Comments for int_NE_code also apply to cmpF_code
730 :: (Reg -> Reg -> Reg -> Instr)
732 -> StixTree -> StixTree
735 cmpF_code instr cond x y
736 = trivialFCode pr instr x y `thenNat` \ register ->
737 getNewRegNCG DoubleRep `thenNat` \ tmp ->
738 getNatLabelNCG `thenNat` \ lbl ->
740 code = registerCode register tmp
741 result = registerName register tmp
743 code__2 dst = code . mkSeqInstrs [
744 OR zeroh (RIImm (ImmInt 1)) dst,
745 BF cond result (ImmCLbl lbl),
746 OR zeroh (RIReg zeroh) dst,
749 returnNat (Any IntRep code__2)
751 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
752 ------------------------------------------------------------
754 getRegister (StInd pk mem)
755 = getAmode mem `thenNat` \ amode ->
757 code = amodeCode amode
758 src = amodeAddr amode
759 size = primRepToSize pk
760 code__2 dst = code . mkSeqInstr (LD size dst src)
762 returnNat (Any pk code__2)
764 getRegister (StInt i)
767 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
769 returnNat (Any IntRep code)
772 code dst = mkSeqInstr (LDI Q dst src)
774 returnNat (Any IntRep code)
776 src = ImmInt (fromInteger i)
781 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
783 returnNat (Any PtrRep code)
786 imm__2 = case imm of Just x -> x
788 #endif {- alpha_TARGET_ARCH -}
790 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
794 getRegister (StFloat f)
795 = getNatLabelNCG `thenNat` \ lbl ->
796 let code dst = toOL [
801 GLD F (ImmAddr (ImmCLbl lbl) 0) dst
804 returnNat (Any FloatRep code)
807 getRegister (StDouble d)
810 = let code dst = unitOL (GLDZ dst)
811 in returnNat (Any DoubleRep code)
814 = let code dst = unitOL (GLD1 dst)
815 in returnNat (Any DoubleRep code)
818 = getNatLabelNCG `thenNat` \ lbl ->
819 let code dst = toOL [
822 DATA DF [ImmDouble d],
824 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
827 returnNat (Any DoubleRep code)
830 getRegister (StMachOp mop [x]) -- unary MachOps
832 MO_NatS_Neg -> trivialUCode (NEGI L) x
833 MO_Nat_Not -> trivialUCode (NOT L) x
834 MO_32U_to_8U -> trivialUCode (AND L (OpImm (ImmInt 255))) x
836 MO_Flt_Neg -> trivialUFCode FloatRep (GNEG F) x
837 MO_Dbl_Neg -> trivialUFCode DoubleRep (GNEG DF) x
839 MO_Flt_Sqrt -> trivialUFCode FloatRep (GSQRT F) x
840 MO_Dbl_Sqrt -> trivialUFCode DoubleRep (GSQRT DF) x
842 MO_Flt_Sin -> trivialUFCode FloatRep (GSIN F) x
843 MO_Dbl_Sin -> trivialUFCode DoubleRep (GSIN DF) x
845 MO_Flt_Cos -> trivialUFCode FloatRep (GCOS F) x
846 MO_Dbl_Cos -> trivialUFCode DoubleRep (GCOS DF) x
848 MO_Flt_Tan -> trivialUFCode FloatRep (GTAN F) x
849 MO_Dbl_Tan -> trivialUFCode DoubleRep (GTAN DF) x
851 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
852 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
853 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
854 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
856 -- Conversions which are a nop on x86
857 MO_NatS_to_32U -> conversionNop WordRep x
858 MO_32U_to_NatS -> conversionNop IntRep x
860 MO_NatU_to_NatS -> conversionNop IntRep x
861 MO_NatS_to_NatU -> conversionNop WordRep x
862 MO_NatP_to_NatU -> conversionNop WordRep x
863 MO_NatU_to_NatP -> conversionNop PtrRep x
864 MO_NatS_to_NatP -> conversionNop PtrRep x
865 MO_NatP_to_NatS -> conversionNop IntRep x
867 MO_Dbl_to_Flt -> conversionNop FloatRep x
868 MO_Flt_to_Dbl -> conversionNop DoubleRep x
870 -- sign-extending widenings
871 MO_8U_to_NatU -> integerExtend False 24 x
872 MO_8S_to_NatS -> integerExtend True 24 x
873 MO_16U_to_NatU -> integerExtend False 16 x
874 MO_16S_to_NatS -> integerExtend True 16 x
875 MO_8U_to_32U -> integerExtend False 24 x
879 (if is_float_op then demote else id)
880 (StCall fn CCallConv DoubleRep
881 [(if is_float_op then promote else id) x])
884 integerExtend signed nBits x
886 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
887 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
890 conversionNop new_rep expr
891 = getRegister expr `thenNat` \ e_code ->
892 returnNat (swizzleRegisterRep e_code new_rep)
894 promote x = StMachOp MO_Flt_to_Dbl [x]
895 demote x = StMachOp MO_Dbl_to_Flt [x]
898 MO_Flt_Exp -> (True, SLIT("exp"))
899 MO_Flt_Log -> (True, SLIT("log"))
901 MO_Flt_Asin -> (True, SLIT("asin"))
902 MO_Flt_Acos -> (True, SLIT("acos"))
903 MO_Flt_Atan -> (True, SLIT("atan"))
905 MO_Flt_Sinh -> (True, SLIT("sinh"))
906 MO_Flt_Cosh -> (True, SLIT("cosh"))
907 MO_Flt_Tanh -> (True, SLIT("tanh"))
909 MO_Dbl_Exp -> (False, SLIT("exp"))
910 MO_Dbl_Log -> (False, SLIT("log"))
912 MO_Dbl_Asin -> (False, SLIT("asin"))
913 MO_Dbl_Acos -> (False, SLIT("acos"))
914 MO_Dbl_Atan -> (False, SLIT("atan"))
916 MO_Dbl_Sinh -> (False, SLIT("sinh"))
917 MO_Dbl_Cosh -> (False, SLIT("cosh"))
918 MO_Dbl_Tanh -> (False, SLIT("tanh"))
920 other -> pprPanic "getRegister(x86) - binary StMachOp (2)"
924 getRegister (StMachOp mop [x, y]) -- dyadic MachOps
926 MO_32U_Gt -> condIntReg GTT x y
927 MO_32U_Ge -> condIntReg GE x y
928 MO_32U_Eq -> condIntReg EQQ x y
929 MO_32U_Ne -> condIntReg NE x y
930 MO_32U_Lt -> condIntReg LTT x y
931 MO_32U_Le -> condIntReg LE x y
933 MO_Nat_Eq -> condIntReg EQQ x y
934 MO_Nat_Ne -> condIntReg NE x y
936 MO_NatS_Gt -> condIntReg GTT x y
937 MO_NatS_Ge -> condIntReg GE x y
938 MO_NatS_Lt -> condIntReg LTT x y
939 MO_NatS_Le -> condIntReg LE x y
941 MO_NatU_Gt -> condIntReg GU x y
942 MO_NatU_Ge -> condIntReg GEU x y
943 MO_NatU_Lt -> condIntReg LU x y
944 MO_NatU_Le -> condIntReg LEU x y
946 MO_Flt_Gt -> condFltReg GTT x y
947 MO_Flt_Ge -> condFltReg GE x y
948 MO_Flt_Eq -> condFltReg EQQ x y
949 MO_Flt_Ne -> condFltReg NE x y
950 MO_Flt_Lt -> condFltReg LTT x y
951 MO_Flt_Le -> condFltReg LE x y
953 MO_Dbl_Gt -> condFltReg GTT x y
954 MO_Dbl_Ge -> condFltReg GE x y
955 MO_Dbl_Eq -> condFltReg EQQ x y
956 MO_Dbl_Ne -> condFltReg NE x y
957 MO_Dbl_Lt -> condFltReg LTT x y
958 MO_Dbl_Le -> condFltReg LE x y
960 MO_Nat_Add -> add_code L x y
961 MO_Nat_Sub -> sub_code L x y
962 MO_NatS_Quot -> trivialCode (IQUOT L) Nothing x y
963 MO_NatS_Rem -> trivialCode (IREM L) Nothing x y
964 MO_NatU_Quot -> trivialCode (QUOT L) Nothing x y
965 MO_NatU_Rem -> trivialCode (REM L) Nothing x y
966 MO_NatS_Mul -> let op = IMUL L in trivialCode op (Just op) x y
967 MO_NatU_Mul -> let op = MUL L in trivialCode op (Just op) x y
968 MO_NatS_MulMayOflo -> imulMayOflo x y
970 MO_Flt_Add -> trivialFCode FloatRep GADD x y
971 MO_Flt_Sub -> trivialFCode FloatRep GSUB x y
972 MO_Flt_Mul -> trivialFCode FloatRep GMUL x y
973 MO_Flt_Div -> trivialFCode FloatRep GDIV x y
975 MO_Dbl_Add -> trivialFCode DoubleRep GADD x y
976 MO_Dbl_Sub -> trivialFCode DoubleRep GSUB x y
977 MO_Dbl_Mul -> trivialFCode DoubleRep GMUL x y
978 MO_Dbl_Div -> trivialFCode DoubleRep GDIV x y
980 MO_Nat_And -> let op = AND L in trivialCode op (Just op) x y
981 MO_Nat_Or -> let op = OR L in trivialCode op (Just op) x y
982 MO_Nat_Xor -> let op = XOR L in trivialCode op (Just op) x y
984 {- Shift ops on x86s have constraints on their source, it
985 either has to be Imm, CL or 1
986 => trivialCode's is not restrictive enough (sigh.)
988 MO_Nat_Shl -> shift_code (SHL L) x y {-False-}
989 MO_Nat_Shr -> shift_code (SHR L) x y {-False-}
990 MO_Nat_Sar -> shift_code (SAR L) x y {-False-}
992 MO_Flt_Pwr -> getRegister (demote
993 (StCall SLIT("pow") CCallConv DoubleRep
994 [promote x, promote y])
996 MO_Dbl_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
998 other -> pprPanic "getRegister(x86) - binary StMachOp (1)" (pprMachOp mop)
1000 promote x = StMachOp MO_Flt_to_Dbl [x]
1001 demote x = StMachOp MO_Dbl_to_Flt [x]
1003 --------------------
1004 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1006 = getNewRegNCG IntRep `thenNat` \ t1 ->
1007 getNewRegNCG IntRep `thenNat` \ t2 ->
1008 getNewRegNCG IntRep `thenNat` \ res_lo ->
1009 getNewRegNCG IntRep `thenNat` \ res_hi ->
1010 getRegister a1 `thenNat` \ reg1 ->
1011 getRegister a2 `thenNat` \ reg2 ->
1012 let code1 = registerCode reg1 t1
1013 code2 = registerCode reg2 t2
1014 src1 = registerName reg1 t1
1015 src2 = registerName reg2 t2
1017 MOV L (OpReg src1) (OpReg res_hi),
1018 MOV L (OpReg src2) (OpReg res_lo),
1019 IMUL64 res_hi res_lo, -- result in res_hi:res_lo
1020 SAR L (ImmInt 31) (OpReg res_lo), -- sign extend lower part
1021 SUB L (OpReg res_hi) (OpReg res_lo), -- compare against upper
1022 MOV L (OpReg res_lo) (OpReg dst)
1023 -- dst==0 if high part == sign extended low part
1026 returnNat (Any IntRep code)
1028 --------------------
1029 shift_code :: (Imm -> Operand -> Instr)
1034 {- Case1: shift length as immediate -}
1035 -- Code is the same as the first eq. for trivialCode -- sigh.
1036 shift_code instr x y{-amount-}
1038 = getRegister x `thenNat` \ regx ->
1041 then registerCodeA regx dst `bind` \ code_x ->
1043 instr imm__2 (OpReg dst)
1044 else registerCodeF regx `bind` \ code_x ->
1045 registerNameF regx `bind` \ r_x ->
1047 MOV L (OpReg r_x) (OpReg dst) `snocOL`
1048 instr imm__2 (OpReg dst)
1050 returnNat (Any IntRep mkcode)
1053 imm__2 = case imm of Just x -> x
1055 {- Case2: shift length is complex (non-immediate) -}
1056 -- Since ECX is always used as a spill temporary, we can't
1057 -- use it here to do non-immediate shifts. No big deal --
1058 -- they are only very rare, and we can use an equivalent
1059 -- test-and-jump sequence which doesn't use ECX.
1060 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
1061 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
1062 shift_code instr x y{-amount-}
1063 = getRegister x `thenNat` \ register1 ->
1064 getRegister y `thenNat` \ register2 ->
1065 getNatLabelNCG `thenNat` \ lbl_test3 ->
1066 getNatLabelNCG `thenNat` \ lbl_test2 ->
1067 getNatLabelNCG `thenNat` \ lbl_test1 ->
1068 getNatLabelNCG `thenNat` \ lbl_test0 ->
1069 getNatLabelNCG `thenNat` \ lbl_after ->
1070 getNewRegNCG IntRep `thenNat` \ tmp ->
1072 = let src_val = registerName register1 dst
1073 code_val = registerCode register1 dst
1074 src_amt = registerName register2 tmp
1075 code_amt = registerCode register2 tmp
1080 MOV L (OpReg src_amt) r_tmp `appOL`
1082 MOV L (OpReg src_val) r_dst `appOL`
1084 COMMENT (_PK_ "begin shift sequence"),
1085 MOV L (OpReg src_val) r_dst,
1086 MOV L (OpReg src_amt) r_tmp,
1088 BT L (ImmInt 4) r_tmp,
1090 instr (ImmInt 16) r_dst,
1093 BT L (ImmInt 3) r_tmp,
1095 instr (ImmInt 8) r_dst,
1098 BT L (ImmInt 2) r_tmp,
1100 instr (ImmInt 4) r_dst,
1103 BT L (ImmInt 1) r_tmp,
1105 instr (ImmInt 2) r_dst,
1108 BT L (ImmInt 0) r_tmp,
1110 instr (ImmInt 1) r_dst,
1113 COMMENT (_PK_ "end shift sequence")
1116 returnNat (Any IntRep code__2)
1118 --------------------
1119 add_code :: Size -> StixExpr -> StixExpr -> NatM Register
1121 add_code sz x (StInt y)
1122 = getRegister x `thenNat` \ register ->
1123 getNewRegNCG IntRep `thenNat` \ tmp ->
1125 code = registerCode register tmp
1126 src1 = registerName register tmp
1127 src2 = ImmInt (fromInteger y)
1130 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1133 returnNat (Any IntRep code__2)
1135 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
1137 --------------------
1138 sub_code :: Size -> StixExpr -> StixExpr -> NatM Register
1140 sub_code sz x (StInt y)
1141 = getRegister x `thenNat` \ register ->
1142 getNewRegNCG IntRep `thenNat` \ tmp ->
1144 code = registerCode register tmp
1145 src1 = registerName register tmp
1146 src2 = ImmInt (-(fromInteger y))
1149 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1152 returnNat (Any IntRep code__2)
1154 sub_code sz x y = trivialCode (SUB sz) Nothing x y
1156 getRegister (StInd pk mem)
1157 | not (is64BitRep pk)
1158 = getAmode mem `thenNat` \ amode ->
1160 code = amodeCode amode
1161 src = amodeAddr amode
1162 size = primRepToSize pk
1163 code__2 dst = code `snocOL`
1164 if pk == DoubleRep || pk == FloatRep
1165 then GLD size src dst
1173 (OpAddr src) (OpReg dst)
1175 returnNat (Any pk code__2)
1177 getRegister (StInt i)
1179 src = ImmInt (fromInteger i)
1182 = unitOL (XOR L (OpReg dst) (OpReg dst))
1184 = unitOL (MOV L (OpImm src) (OpReg dst))
1186 returnNat (Any IntRep code)
1190 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
1192 returnNat (Any PtrRep code)
1194 = ncgPrimopMoan "getRegister(x86)" (pprStixExpr leaf)
1197 imm__2 = case imm of Just x -> x
1199 #endif {- i386_TARGET_ARCH -}
1201 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1203 #if sparc_TARGET_ARCH
1205 getRegister (StFloat d)
1206 = getNatLabelNCG `thenNat` \ lbl ->
1207 getNewRegNCG PtrRep `thenNat` \ tmp ->
1208 let code dst = toOL [
1209 SEGMENT DataSegment,
1211 DATA F [ImmFloat d],
1212 SEGMENT TextSegment,
1213 SETHI (HI (ImmCLbl lbl)) tmp,
1214 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1216 returnNat (Any FloatRep code)
1218 getRegister (StDouble d)
1219 = getNatLabelNCG `thenNat` \ lbl ->
1220 getNewRegNCG PtrRep `thenNat` \ tmp ->
1221 let code dst = toOL [
1222 SEGMENT DataSegment,
1224 DATA DF [ImmDouble d],
1225 SEGMENT TextSegment,
1226 SETHI (HI (ImmCLbl lbl)) tmp,
1227 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1229 returnNat (Any DoubleRep code)
1232 getRegister (StMachOp mop [x]) -- unary PrimOps
1234 MO_NatS_Neg -> trivialUCode (SUB False False g0) x
1235 MO_Nat_Not -> trivialUCode (XNOR False g0) x
1237 MO_Flt_Neg -> trivialUFCode FloatRep (FNEG F) x
1238 MO_Dbl_Neg -> trivialUFCode DoubleRep (FNEG DF) x
1240 MO_Dbl_to_Flt -> coerceDbl2Flt x
1241 MO_Flt_to_Dbl -> coerceFlt2Dbl x
1243 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
1244 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
1245 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
1246 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
1248 -- Conversions which are a nop on sparc
1249 MO_32U_to_NatS -> conversionNop IntRep x
1250 MO_NatS_to_32U -> conversionNop WordRep x
1252 MO_NatU_to_NatS -> conversionNop IntRep x
1253 MO_NatS_to_NatU -> conversionNop WordRep x
1254 MO_NatP_to_NatU -> conversionNop WordRep x
1255 MO_NatU_to_NatP -> conversionNop PtrRep x
1256 MO_NatS_to_NatP -> conversionNop PtrRep x
1257 MO_NatP_to_NatS -> conversionNop IntRep x
1259 -- sign-extending widenings
1260 MO_8U_to_NatU -> integerExtend False 24 x
1261 MO_8S_to_NatS -> integerExtend True 24 x
1262 MO_16U_to_NatU -> integerExtend False 16 x
1263 MO_16S_to_NatS -> integerExtend True 16 x
1266 let fixed_x = if is_float_op -- promote to double
1267 then StMachOp MO_Flt_to_Dbl [x]
1270 getRegister (StCall fn CCallConv DoubleRep [fixed_x])
1272 integerExtend signed nBits x
1274 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
1275 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
1277 conversionNop new_rep expr
1278 = getRegister expr `thenNat` \ e_code ->
1279 returnNat (swizzleRegisterRep e_code new_rep)
1283 MO_Flt_Exp -> (True, SLIT("exp"))
1284 MO_Flt_Log -> (True, SLIT("log"))
1285 MO_Flt_Sqrt -> (True, SLIT("sqrt"))
1287 MO_Flt_Sin -> (True, SLIT("sin"))
1288 MO_Flt_Cos -> (True, SLIT("cos"))
1289 MO_Flt_Tan -> (True, SLIT("tan"))
1291 MO_Flt_Asin -> (True, SLIT("asin"))
1292 MO_Flt_Acos -> (True, SLIT("acos"))
1293 MO_Flt_Atan -> (True, SLIT("atan"))
1295 MO_Flt_Sinh -> (True, SLIT("sinh"))
1296 MO_Flt_Cosh -> (True, SLIT("cosh"))
1297 MO_Flt_Tanh -> (True, SLIT("tanh"))
1299 MO_Dbl_Exp -> (False, SLIT("exp"))
1300 MO_Dbl_Log -> (False, SLIT("log"))
1301 MO_Dbl_Sqrt -> (False, SLIT("sqrt"))
1303 MO_Dbl_Sin -> (False, SLIT("sin"))
1304 MO_Dbl_Cos -> (False, SLIT("cos"))
1305 MO_Dbl_Tan -> (False, SLIT("tan"))
1307 MO_Dbl_Asin -> (False, SLIT("asin"))
1308 MO_Dbl_Acos -> (False, SLIT("acos"))
1309 MO_Dbl_Atan -> (False, SLIT("atan"))
1311 MO_Dbl_Sinh -> (False, SLIT("sinh"))
1312 MO_Dbl_Cosh -> (False, SLIT("cosh"))
1313 MO_Dbl_Tanh -> (False, SLIT("tanh"))
1315 other -> pprPanic "getRegister(sparc) - binary StMachOp (2)"
1319 getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
1321 MO_32U_Gt -> condIntReg GTT x y
1322 MO_32U_Ge -> condIntReg GE x y
1323 MO_32U_Eq -> condIntReg EQQ x y
1324 MO_32U_Ne -> condIntReg NE x y
1325 MO_32U_Lt -> condIntReg LTT x y
1326 MO_32U_Le -> condIntReg LE x y
1328 MO_Nat_Eq -> condIntReg EQQ x y
1329 MO_Nat_Ne -> condIntReg NE x y
1331 MO_NatS_Gt -> condIntReg GTT x y
1332 MO_NatS_Ge -> condIntReg GE x y
1333 MO_NatS_Lt -> condIntReg LTT x y
1334 MO_NatS_Le -> condIntReg LE x y
1336 MO_NatU_Gt -> condIntReg GU x y
1337 MO_NatU_Ge -> condIntReg GEU x y
1338 MO_NatU_Lt -> condIntReg LU x y
1339 MO_NatU_Le -> condIntReg LEU x y
1341 MO_Flt_Gt -> condFltReg GTT x y
1342 MO_Flt_Ge -> condFltReg GE x y
1343 MO_Flt_Eq -> condFltReg EQQ x y
1344 MO_Flt_Ne -> condFltReg NE x y
1345 MO_Flt_Lt -> condFltReg LTT x y
1346 MO_Flt_Le -> condFltReg LE x y
1348 MO_Dbl_Gt -> condFltReg GTT x y
1349 MO_Dbl_Ge -> condFltReg GE x y
1350 MO_Dbl_Eq -> condFltReg EQQ x y
1351 MO_Dbl_Ne -> condFltReg NE x y
1352 MO_Dbl_Lt -> condFltReg LTT x y
1353 MO_Dbl_Le -> condFltReg LE x y
1355 MO_Nat_Add -> trivialCode (ADD False False) x y
1356 MO_Nat_Sub -> trivialCode (SUB False False) x y
1358 MO_NatS_Mul -> trivialCode (SMUL False) x y
1359 MO_NatU_Mul -> trivialCode (UMUL False) x y
1360 MO_NatS_MulMayOflo -> imulMayOflo x y
1362 -- ToDo: teach about V8+ SPARC div instructions
1363 MO_NatS_Quot -> idiv SLIT(".div") x y
1364 MO_NatS_Rem -> idiv SLIT(".rem") x y
1365 MO_NatU_Quot -> idiv SLIT(".udiv") x y
1366 MO_NatU_Rem -> idiv SLIT(".urem") x y
1368 MO_Flt_Add -> trivialFCode FloatRep FADD x y
1369 MO_Flt_Sub -> trivialFCode FloatRep FSUB x y
1370 MO_Flt_Mul -> trivialFCode FloatRep FMUL x y
1371 MO_Flt_Div -> trivialFCode FloatRep FDIV x y
1373 MO_Dbl_Add -> trivialFCode DoubleRep FADD x y
1374 MO_Dbl_Sub -> trivialFCode DoubleRep FSUB x y
1375 MO_Dbl_Mul -> trivialFCode DoubleRep FMUL x y
1376 MO_Dbl_Div -> trivialFCode DoubleRep FDIV x y
1378 MO_Nat_And -> trivialCode (AND False) x y
1379 MO_Nat_Or -> trivialCode (OR False) x y
1380 MO_Nat_Xor -> trivialCode (XOR False) x y
1382 MO_Nat_Shl -> trivialCode SLL x y
1383 MO_Nat_Shr -> trivialCode SRL x y
1384 MO_Nat_Sar -> trivialCode SRA x y
1386 MO_Flt_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1387 [promote x, promote y])
1388 where promote x = StMachOp MO_Flt_to_Dbl [x]
1389 MO_Dbl_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1392 other -> pprPanic "getRegister(sparc) - binary StMachOp (1)" (pprMachOp mop)
1394 idiv fn x y = getRegister (StCall fn CCallConv IntRep [x, y])
1396 --------------------
1397 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1399 = getNewRegNCG IntRep `thenNat` \ t1 ->
1400 getNewRegNCG IntRep `thenNat` \ t2 ->
1401 getNewRegNCG IntRep `thenNat` \ res_lo ->
1402 getNewRegNCG IntRep `thenNat` \ res_hi ->
1403 getRegister a1 `thenNat` \ reg1 ->
1404 getRegister a2 `thenNat` \ reg2 ->
1405 let code1 = registerCode reg1 t1
1406 code2 = registerCode reg2 t2
1407 src1 = registerName reg1 t1
1408 src2 = registerName reg2 t2
1410 SMUL False src1 (RIReg src2) res_lo,
1412 SRA res_lo (RIImm (ImmInt 31)) res_lo,
1413 SUB False False res_lo (RIReg res_hi) dst
1416 returnNat (Any IntRep code)
1418 getRegister (StInd pk mem)
1419 = getAmode mem `thenNat` \ amode ->
1421 code = amodeCode amode
1422 src = amodeAddr amode
1423 size = primRepToSize pk
1424 code__2 dst = code `snocOL` LD size src dst
1426 returnNat (Any pk code__2)
1428 getRegister (StInt i)
1431 src = ImmInt (fromInteger i)
1432 code dst = unitOL (OR False g0 (RIImm src) dst)
1434 returnNat (Any IntRep code)
1440 SETHI (HI imm__2) dst,
1441 OR False dst (RIImm (LO imm__2)) dst]
1443 returnNat (Any PtrRep code)
1445 = ncgPrimopMoan "getRegister(sparc)" (pprStixExpr leaf)
1448 imm__2 = case imm of Just x -> x
1450 #endif {- sparc_TARGET_ARCH -}
1452 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1456 %************************************************************************
1458 \subsection{The @Amode@ type}
1460 %************************************************************************
1462 @Amode@s: Memory addressing modes passed up the tree.
1464 data Amode = Amode MachRegsAddr InstrBlock
1466 amodeAddr (Amode addr _) = addr
1467 amodeCode (Amode _ code) = code
1470 Now, given a tree (the argument to an StInd) that references memory,
1471 produce a suitable addressing mode.
1473 A Rule of the Game (tm) for Amodes: use of the addr bit must
1474 immediately follow use of the code part, since the code part puts
1475 values in registers which the addr then refers to. So you can't put
1476 anything in between, lest it overwrite some of those registers. If
1477 you need to do some other computation between the code part and use of
1478 the addr bit, first store the effective address from the amode in a
1479 temporary, then do the other computation, and then use the temporary:
1483 ... other computation ...
1487 getAmode :: StixExpr -> NatM Amode
1489 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1491 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1493 #if alpha_TARGET_ARCH
1495 getAmode (StPrim IntSubOp [x, StInt i])
1496 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1497 getRegister x `thenNat` \ register ->
1499 code = registerCode register tmp
1500 reg = registerName register tmp
1501 off = ImmInt (-(fromInteger i))
1503 returnNat (Amode (AddrRegImm reg off) code)
1505 getAmode (StPrim IntAddOp [x, StInt i])
1506 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1507 getRegister x `thenNat` \ register ->
1509 code = registerCode register tmp
1510 reg = registerName register tmp
1511 off = ImmInt (fromInteger i)
1513 returnNat (Amode (AddrRegImm reg off) code)
1517 = returnNat (Amode (AddrImm imm__2) id)
1520 imm__2 = case imm of Just x -> x
1523 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1524 getRegister other `thenNat` \ register ->
1526 code = registerCode register tmp
1527 reg = registerName register tmp
1529 returnNat (Amode (AddrReg reg) code)
1531 #endif {- alpha_TARGET_ARCH -}
1533 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1535 #if i386_TARGET_ARCH
1537 -- This is all just ridiculous, since it carefully undoes
1538 -- what mangleIndexTree has just done.
1539 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1540 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1541 getRegister x `thenNat` \ register ->
1543 code = registerCode register tmp
1544 reg = registerName register tmp
1545 off = ImmInt (-(fromInteger i))
1547 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1549 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1551 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1554 imm__2 = case imm of Just x -> x
1556 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1557 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1558 getRegister x `thenNat` \ register ->
1560 code = registerCode register tmp
1561 reg = registerName register tmp
1562 off = ImmInt (fromInteger i)
1564 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1566 getAmode (StMachOp MO_Nat_Add [x, StMachOp MO_Nat_Shl [y, StInt shift]])
1567 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1568 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1569 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1570 getRegister x `thenNat` \ register1 ->
1571 getRegister y `thenNat` \ register2 ->
1573 code1 = registerCode register1 tmp1
1574 reg1 = registerName register1 tmp1
1575 code2 = registerCode register2 tmp2
1576 reg2 = registerName register2 tmp2
1577 code__2 = code1 `appOL` code2
1578 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1580 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1585 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1588 imm__2 = case imm of Just x -> x
1591 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1592 getRegister other `thenNat` \ register ->
1594 code = registerCode register tmp
1595 reg = registerName register tmp
1597 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1599 #endif {- i386_TARGET_ARCH -}
1601 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1603 #if sparc_TARGET_ARCH
1605 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1607 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1608 getRegister x `thenNat` \ register ->
1610 code = registerCode register tmp
1611 reg = registerName register tmp
1612 off = ImmInt (-(fromInteger i))
1614 returnNat (Amode (AddrRegImm reg off) code)
1617 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1619 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1620 getRegister x `thenNat` \ register ->
1622 code = registerCode register tmp
1623 reg = registerName register tmp
1624 off = ImmInt (fromInteger i)
1626 returnNat (Amode (AddrRegImm reg off) code)
1628 getAmode (StMachOp MO_Nat_Add [x, y])
1629 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1630 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1631 getRegister x `thenNat` \ register1 ->
1632 getRegister y `thenNat` \ register2 ->
1634 code1 = registerCode register1 tmp1
1635 reg1 = registerName register1 tmp1
1636 code2 = registerCode register2 tmp2
1637 reg2 = registerName register2 tmp2
1638 code__2 = code1 `appOL` code2
1640 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1644 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1646 code = unitOL (SETHI (HI imm__2) tmp)
1648 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1651 imm__2 = case imm of Just x -> x
1654 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1655 getRegister other `thenNat` \ register ->
1657 code = registerCode register tmp
1658 reg = registerName register tmp
1661 returnNat (Amode (AddrRegImm reg off) code)
1663 #endif {- sparc_TARGET_ARCH -}
1665 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1668 %************************************************************************
1670 \subsection{The @CondCode@ type}
1672 %************************************************************************
1674 Condition codes passed up the tree.
1676 data CondCode = CondCode Bool Cond InstrBlock
1678 condName (CondCode _ cond _) = cond
1679 condFloat (CondCode is_float _ _) = is_float
1680 condCode (CondCode _ _ code) = code
1683 Set up a condition code for a conditional branch.
1686 getCondCode :: StixExpr -> NatM CondCode
1688 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1690 #if alpha_TARGET_ARCH
1691 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1692 #endif {- alpha_TARGET_ARCH -}
1694 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1696 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1697 -- yes, they really do seem to want exactly the same!
1699 getCondCode (StMachOp mop [x, y])
1701 MO_32U_Gt -> condIntCode GTT x y
1702 MO_32U_Ge -> condIntCode GE x y
1703 MO_32U_Eq -> condIntCode EQQ x y
1704 MO_32U_Ne -> condIntCode NE x y
1705 MO_32U_Lt -> condIntCode LTT x y
1706 MO_32U_Le -> condIntCode LE x y
1708 MO_Nat_Eq -> condIntCode EQQ x y
1709 MO_Nat_Ne -> condIntCode NE x y
1711 MO_NatS_Gt -> condIntCode GTT x y
1712 MO_NatS_Ge -> condIntCode GE x y
1713 MO_NatS_Lt -> condIntCode LTT x y
1714 MO_NatS_Le -> condIntCode LE x y
1716 MO_NatU_Gt -> condIntCode GU x y
1717 MO_NatU_Ge -> condIntCode GEU x y
1718 MO_NatU_Lt -> condIntCode LU x y
1719 MO_NatU_Le -> condIntCode LEU x y
1721 MO_Flt_Gt -> condFltCode GTT x y
1722 MO_Flt_Ge -> condFltCode GE x y
1723 MO_Flt_Eq -> condFltCode EQQ x y
1724 MO_Flt_Ne -> condFltCode NE x y
1725 MO_Flt_Lt -> condFltCode LTT x y
1726 MO_Flt_Le -> condFltCode LE x y
1728 MO_Dbl_Gt -> condFltCode GTT x y
1729 MO_Dbl_Ge -> condFltCode GE x y
1730 MO_Dbl_Eq -> condFltCode EQQ x y
1731 MO_Dbl_Ne -> condFltCode NE x y
1732 MO_Dbl_Lt -> condFltCode LTT x y
1733 MO_Dbl_Le -> condFltCode LE x y
1735 other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
1737 getCondCode other = pprPanic "getCondCode(2)(x86,sparc)" (pprStixExpr other)
1739 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1741 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1746 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1747 passed back up the tree.
1750 condIntCode, condFltCode :: Cond -> StixExpr -> StixExpr -> NatM CondCode
1752 #if alpha_TARGET_ARCH
1753 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1754 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1755 #endif {- alpha_TARGET_ARCH -}
1757 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1758 #if i386_TARGET_ARCH
1760 -- memory vs immediate
1761 condIntCode cond (StInd pk x) y
1762 | Just i <- maybeImm y
1763 = getAmode x `thenNat` \ amode ->
1765 code1 = amodeCode amode
1766 x__2 = amodeAddr amode
1767 sz = primRepToSize pk
1768 code__2 = code1 `snocOL`
1769 CMP sz (OpImm i) (OpAddr x__2)
1771 returnNat (CondCode False cond code__2)
1774 condIntCode cond x (StInt 0)
1775 = getRegister x `thenNat` \ register1 ->
1776 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1778 code1 = registerCode register1 tmp1
1779 src1 = registerName register1 tmp1
1780 code__2 = code1 `snocOL`
1781 TEST L (OpReg src1) (OpReg src1)
1783 returnNat (CondCode False cond code__2)
1785 -- anything vs immediate
1786 condIntCode cond x y
1787 | Just i <- maybeImm y
1788 = getRegister x `thenNat` \ register1 ->
1789 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1791 code1 = registerCode register1 tmp1
1792 src1 = registerName register1 tmp1
1793 code__2 = code1 `snocOL`
1794 CMP L (OpImm i) (OpReg src1)
1796 returnNat (CondCode False cond code__2)
1798 -- memory vs anything
1799 condIntCode cond (StInd pk x) y
1800 = getAmode x `thenNat` \ amode_x ->
1801 getRegister y `thenNat` \ reg_y ->
1802 getNewRegNCG IntRep `thenNat` \ tmp ->
1804 c_x = amodeCode amode_x
1805 am_x = amodeAddr amode_x
1806 c_y = registerCode reg_y tmp
1807 r_y = registerName reg_y tmp
1808 sz = primRepToSize pk
1810 -- optimisation: if there's no code for x, just an amode,
1811 -- use whatever reg y winds up in. Assumes that c_y doesn't
1812 -- clobber any regs in the amode am_x, which I'm not sure is
1813 -- justified. The otherwise clause makes the same assumption.
1814 code__2 | isNilOL c_x
1816 CMP sz (OpReg r_y) (OpAddr am_x)
1820 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1822 CMP sz (OpReg tmp) (OpAddr am_x)
1824 returnNat (CondCode False cond code__2)
1826 -- anything vs memory
1828 condIntCode cond y (StInd pk x)
1829 = getAmode x `thenNat` \ amode_x ->
1830 getRegister y `thenNat` \ reg_y ->
1831 getNewRegNCG IntRep `thenNat` \ tmp ->
1833 c_x = amodeCode amode_x
1834 am_x = amodeAddr amode_x
1835 c_y = registerCode reg_y tmp
1836 r_y = registerName reg_y tmp
1837 sz = primRepToSize pk
1838 -- same optimisation and nagging doubts as previous clause
1839 code__2 | isNilOL c_x
1841 CMP sz (OpAddr am_x) (OpReg r_y)
1845 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1847 CMP sz (OpAddr am_x) (OpReg tmp)
1849 returnNat (CondCode False cond code__2)
1851 -- anything vs anything
1852 condIntCode cond x y
1853 = getRegister x `thenNat` \ register1 ->
1854 getRegister y `thenNat` \ register2 ->
1855 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1856 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1858 code1 = registerCode register1 tmp1
1859 src1 = registerName register1 tmp1
1860 code2 = registerCode register2 tmp2
1861 src2 = registerName register2 tmp2
1862 code__2 = code1 `snocOL`
1863 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1865 CMP L (OpReg src2) (OpReg tmp1)
1867 returnNat (CondCode False cond code__2)
1870 condFltCode cond x y
1871 = getRegister x `thenNat` \ register1 ->
1872 getRegister y `thenNat` \ register2 ->
1873 getNewRegNCG (registerRep register1)
1875 getNewRegNCG (registerRep register2)
1877 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1879 pk1 = registerRep register1
1880 code1 = registerCode register1 tmp1
1881 src1 = registerName register1 tmp1
1883 code2 = registerCode register2 tmp2
1884 src2 = registerName register2 tmp2
1886 code__2 | isAny register1
1887 = code1 `appOL` -- result in tmp1
1889 GCMP (primRepToSize pk1) tmp1 src2
1893 GMOV src1 tmp1 `appOL`
1895 GCMP (primRepToSize pk1) tmp1 src2
1897 {- On the 486, the flags set by FP compare are the unsigned ones!
1898 (This looks like a HACK to me. WDP 96/03)
1900 fix_FP_cond :: Cond -> Cond
1902 fix_FP_cond GE = GEU
1903 fix_FP_cond GTT = GU
1904 fix_FP_cond LTT = LU
1905 fix_FP_cond LE = LEU
1906 fix_FP_cond any = any
1908 returnNat (CondCode True (fix_FP_cond cond) code__2)
1910 #endif {- i386_TARGET_ARCH -}
1912 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1914 #if sparc_TARGET_ARCH
1916 condIntCode cond x (StInt y)
1918 = getRegister x `thenNat` \ register ->
1919 getNewRegNCG IntRep `thenNat` \ tmp ->
1921 code = registerCode register tmp
1922 src1 = registerName register tmp
1923 src2 = ImmInt (fromInteger y)
1924 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1926 returnNat (CondCode False cond code__2)
1928 condIntCode cond x y
1929 = getRegister x `thenNat` \ register1 ->
1930 getRegister y `thenNat` \ register2 ->
1931 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1932 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1934 code1 = registerCode register1 tmp1
1935 src1 = registerName register1 tmp1
1936 code2 = registerCode register2 tmp2
1937 src2 = registerName register2 tmp2
1938 code__2 = code1 `appOL` code2 `snocOL`
1939 SUB False True src1 (RIReg src2) g0
1941 returnNat (CondCode False cond code__2)
1944 condFltCode cond x y
1945 = getRegister x `thenNat` \ register1 ->
1946 getRegister y `thenNat` \ register2 ->
1947 getNewRegNCG (registerRep register1)
1949 getNewRegNCG (registerRep register2)
1951 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1953 promote x = FxTOy F DF x tmp
1955 pk1 = registerRep register1
1956 code1 = registerCode register1 tmp1
1957 src1 = registerName register1 tmp1
1959 pk2 = registerRep register2
1960 code2 = registerCode register2 tmp2
1961 src2 = registerName register2 tmp2
1965 code1 `appOL` code2 `snocOL`
1966 FCMP True (primRepToSize pk1) src1 src2
1967 else if pk1 == FloatRep then
1968 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1969 FCMP True DF tmp src2
1971 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1972 FCMP True DF src1 tmp
1974 returnNat (CondCode True cond code__2)
1976 #endif {- sparc_TARGET_ARCH -}
1978 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1981 %************************************************************************
1983 \subsection{Generating assignments}
1985 %************************************************************************
1987 Assignments are really at the heart of the whole code generation
1988 business. Almost all top-level nodes of any real importance are
1989 assignments, which correspond to loads, stores, or register transfers.
1990 If we're really lucky, some of the register transfers will go away,
1991 because we can use the destination register to complete the code
1992 generation for the right hand side. This only fails when the right
1993 hand side is forced into a fixed register (e.g. the result of a call).
1996 assignMem_IntCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
1997 assignReg_IntCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
1999 assignMem_FltCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
2000 assignReg_FltCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
2002 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2004 #if alpha_TARGET_ARCH
2006 assignIntCode pk (StInd _ dst) src
2007 = getNewRegNCG IntRep `thenNat` \ tmp ->
2008 getAmode dst `thenNat` \ amode ->
2009 getRegister src `thenNat` \ register ->
2011 code1 = amodeCode amode []
2012 dst__2 = amodeAddr amode
2013 code2 = registerCode register tmp []
2014 src__2 = registerName register tmp
2015 sz = primRepToSize pk
2016 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2020 assignIntCode pk dst src
2021 = getRegister dst `thenNat` \ register1 ->
2022 getRegister src `thenNat` \ register2 ->
2024 dst__2 = registerName register1 zeroh
2025 code = registerCode register2 dst__2
2026 src__2 = registerName register2 dst__2
2027 code__2 = if isFixed register2
2028 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
2033 #endif {- alpha_TARGET_ARCH -}
2035 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2037 #if i386_TARGET_ARCH
2039 -- non-FP assignment to memory
2040 assignMem_IntCode pk addr src
2041 = getAmode addr `thenNat` \ amode ->
2042 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
2043 getNewRegNCG PtrRep `thenNat` \ tmp ->
2045 -- In general, if the address computation for dst may require
2046 -- some insns preceding the addressing mode itself. So there's
2047 -- no guarantee that the code for dst and the code for src won't
2048 -- write the same register. This means either the address or
2049 -- the value needs to be copied into a temporary. We detect the
2050 -- common case where the amode has no code, and elide the copy.
2051 codea = amodeCode amode
2052 dst__a = amodeAddr amode
2054 code | isNilOL codea
2056 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
2059 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
2061 MOV (primRepToSize pk) opsrc
2062 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
2068 -> NatM (InstrBlock,Operand) -- code, operator
2071 | Just x <- maybeImm op
2072 = returnNat (nilOL, OpImm x)
2075 = getRegister op `thenNat` \ register ->
2076 getNewRegNCG (registerRep register)
2078 let code = registerCode register tmp
2079 reg = registerName register tmp
2081 returnNat (code, OpReg reg)
2083 -- Assign; dst is a reg, rhs is mem
2084 assignReg_IntCode pk reg (StInd pks src)
2085 = getNewRegNCG PtrRep `thenNat` \ tmp ->
2086 getAmode src `thenNat` \ amode ->
2087 getRegisterReg reg `thenNat` \ reg_dst ->
2089 c_addr = amodeCode amode
2090 am_addr = amodeAddr amode
2091 r_dst = registerName reg_dst tmp
2092 szs = primRepToSize pks
2101 code = c_addr `snocOL`
2102 opc (OpAddr am_addr) (OpReg r_dst)
2106 -- dst is a reg, but src could be anything
2107 assignReg_IntCode pk reg src
2108 = getRegisterReg reg `thenNat` \ registerd ->
2109 getRegister src `thenNat` \ registers ->
2110 getNewRegNCG IntRep `thenNat` \ tmp ->
2112 r_dst = registerName registerd tmp
2113 r_src = registerName registers r_dst
2114 c_src = registerCode registers r_dst
2116 code = c_src `snocOL`
2117 MOV L (OpReg r_src) (OpReg r_dst)
2121 #endif {- i386_TARGET_ARCH -}
2123 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2125 #if sparc_TARGET_ARCH
2127 assignMem_IntCode pk addr src
2128 = getNewRegNCG IntRep `thenNat` \ tmp ->
2129 getAmode addr `thenNat` \ amode ->
2130 getRegister src `thenNat` \ register ->
2132 code1 = amodeCode amode
2133 dst__2 = amodeAddr amode
2134 code2 = registerCode register tmp
2135 src__2 = registerName register tmp
2136 sz = primRepToSize pk
2137 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
2141 assignReg_IntCode pk reg src
2142 = getRegister src `thenNat` \ register2 ->
2143 getRegisterReg reg `thenNat` \ register1 ->
2145 dst__2 = registerName register1 g0
2146 code = registerCode register2 dst__2
2147 src__2 = registerName register2 dst__2
2148 code__2 = if isFixed register2
2149 then code `snocOL` OR False g0 (RIReg src__2) dst__2
2154 #endif {- sparc_TARGET_ARCH -}
2156 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2159 % --------------------------------
2160 Floating-point assignments:
2161 % --------------------------------
2164 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2165 #if alpha_TARGET_ARCH
2167 assignFltCode pk (StInd _ dst) src
2168 = getNewRegNCG pk `thenNat` \ tmp ->
2169 getAmode dst `thenNat` \ amode ->
2170 getRegister src `thenNat` \ register ->
2172 code1 = amodeCode amode []
2173 dst__2 = amodeAddr amode
2174 code2 = registerCode register tmp []
2175 src__2 = registerName register tmp
2176 sz = primRepToSize pk
2177 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2181 assignFltCode pk dst src
2182 = getRegister dst `thenNat` \ register1 ->
2183 getRegister src `thenNat` \ register2 ->
2185 dst__2 = registerName register1 zeroh
2186 code = registerCode register2 dst__2
2187 src__2 = registerName register2 dst__2
2188 code__2 = if isFixed register2
2189 then code . mkSeqInstr (FMOV src__2 dst__2)
2194 #endif {- alpha_TARGET_ARCH -}
2196 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2198 #if i386_TARGET_ARCH
2200 -- Floating point assignment to memory
2201 assignMem_FltCode pk addr src
2202 = getRegister src `thenNat` \ reg_src ->
2203 getRegister addr `thenNat` \ reg_addr ->
2204 getNewRegNCG pk `thenNat` \ tmp_src ->
2205 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
2206 let r_src = registerName reg_src tmp_src
2207 c_src = registerCode reg_src tmp_src
2208 r_addr = registerName reg_addr tmp_addr
2209 c_addr = registerCode reg_addr tmp_addr
2210 sz = primRepToSize pk
2212 code = c_src `appOL`
2213 -- no need to preserve r_src across the addr computation,
2214 -- since r_src must be a float reg
2215 -- whilst r_addr is an int reg
2218 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
2222 -- Floating point assignment to a register/temporary
2223 assignReg_FltCode pk reg src
2224 = getRegisterReg reg `thenNat` \ reg_dst ->
2225 getRegister src `thenNat` \ reg_src ->
2226 getNewRegNCG pk `thenNat` \ tmp ->
2228 r_dst = registerName reg_dst tmp
2229 r_src = registerName reg_src r_dst
2230 c_src = registerCode reg_src r_dst
2232 code = if isFixed reg_src
2233 then c_src `snocOL` GMOV r_src r_dst
2239 #endif {- i386_TARGET_ARCH -}
2241 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2243 #if sparc_TARGET_ARCH
2245 -- Floating point assignment to memory
2246 assignMem_FltCode pk addr src
2247 = getNewRegNCG pk `thenNat` \ tmp1 ->
2248 getAmode addr `thenNat` \ amode ->
2249 getRegister src `thenNat` \ register ->
2251 sz = primRepToSize pk
2252 dst__2 = amodeAddr amode
2254 code1 = amodeCode amode
2255 code2 = registerCode register tmp1
2257 src__2 = registerName register tmp1
2258 pk__2 = registerRep register
2259 sz__2 = primRepToSize pk__2
2261 code__2 = code1 `appOL` code2 `appOL`
2263 then unitOL (ST sz src__2 dst__2)
2264 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
2268 -- Floating point assignment to a register/temporary
2269 -- Why is this so bizarrely ugly?
2270 assignReg_FltCode pk reg src
2271 = getRegisterReg reg `thenNat` \ register1 ->
2272 getRegister src `thenNat` \ register2 ->
2274 pk__2 = registerRep register2
2275 sz__2 = primRepToSize pk__2
2277 getNewRegNCG pk__2 `thenNat` \ tmp ->
2279 sz = primRepToSize pk
2280 dst__2 = registerName register1 g0 -- must be Fixed
2281 reg__2 = if pk /= pk__2 then tmp else dst__2
2282 code = registerCode register2 reg__2
2283 src__2 = registerName register2 reg__2
2286 code `snocOL` FxTOy sz__2 sz src__2 dst__2
2287 else if isFixed register2 then
2288 code `snocOL` FMOV sz src__2 dst__2
2294 #endif {- sparc_TARGET_ARCH -}
2296 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2299 %************************************************************************
2301 \subsection{Generating an unconditional branch}
2303 %************************************************************************
2305 We accept two types of targets: an immediate CLabel or a tree that
2306 gets evaluated into a register. Any CLabels which are AsmTemporaries
2307 are assumed to be in the local block of code, close enough for a
2308 branch instruction. Other CLabels are assumed to be far away.
2310 (If applicable) Do not fill the delay slots here; you will confuse the
2314 genJump :: DestInfo -> StixExpr{-the branch target-} -> NatM InstrBlock
2316 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2318 #if alpha_TARGET_ARCH
2320 genJump (StCLbl lbl)
2321 | isAsmTemp lbl = returnInstr (BR target)
2322 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2324 target = ImmCLbl lbl
2327 = getRegister tree `thenNat` \ register ->
2328 getNewRegNCG PtrRep `thenNat` \ tmp ->
2330 dst = registerName register pv
2331 code = registerCode register pv
2332 target = registerName register pv
2334 if isFixed register then
2335 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2337 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2339 #endif {- alpha_TARGET_ARCH -}
2341 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2343 #if i386_TARGET_ARCH
2345 genJump dsts (StInd pk mem)
2346 = getAmode mem `thenNat` \ amode ->
2348 code = amodeCode amode
2349 target = amodeAddr amode
2351 returnNat (code `snocOL` JMP dsts (OpAddr target))
2355 = returnNat (unitOL (JMP dsts (OpImm target)))
2358 = getRegister tree `thenNat` \ register ->
2359 getNewRegNCG PtrRep `thenNat` \ tmp ->
2361 code = registerCode register tmp
2362 target = registerName register tmp
2364 returnNat (code `snocOL` JMP dsts (OpReg target))
2367 target = case imm of Just x -> x
2369 #endif {- i386_TARGET_ARCH -}
2371 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2373 #if sparc_TARGET_ARCH
2375 genJump dsts (StCLbl lbl)
2376 | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
2377 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2378 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
2380 target = ImmCLbl lbl
2383 = getRegister tree `thenNat` \ register ->
2384 getNewRegNCG PtrRep `thenNat` \ tmp ->
2386 code = registerCode register tmp
2387 target = registerName register tmp
2389 returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
2391 #endif {- sparc_TARGET_ARCH -}
2393 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2396 %************************************************************************
2398 \subsection{Conditional jumps}
2400 %************************************************************************
2402 Conditional jumps are always to local labels, so we can use branch
2403 instructions. We peek at the arguments to decide what kind of
2406 ALPHA: For comparisons with 0, we're laughing, because we can just do
2407 the desired conditional branch.
2409 I386: First, we have to ensure that the condition
2410 codes are set according to the supplied comparison operation.
2412 SPARC: First, we have to ensure that the condition codes are set
2413 according to the supplied comparison operation. We generate slightly
2414 different code for floating point comparisons, because a floating
2415 point operation cannot directly precede a @BF@. We assume the worst
2416 and fill that slot with a @NOP@.
2418 SPARC: Do not fill the delay slots here; you will confuse the register
2423 :: CLabel -- the branch target
2424 -> StixExpr -- the condition on which to branch
2427 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2429 #if alpha_TARGET_ARCH
2431 genCondJump lbl (StPrim op [x, StInt 0])
2432 = getRegister x `thenNat` \ register ->
2433 getNewRegNCG (registerRep register)
2436 code = registerCode register tmp
2437 value = registerName register tmp
2438 pk = registerRep register
2439 target = ImmCLbl lbl
2441 returnSeq code [BI (cmpOp op) value target]
2443 cmpOp CharGtOp = GTT
2445 cmpOp CharEqOp = EQQ
2447 cmpOp CharLtOp = LTT
2456 cmpOp WordGeOp = ALWAYS
2457 cmpOp WordEqOp = EQQ
2459 cmpOp WordLtOp = NEVER
2460 cmpOp WordLeOp = EQQ
2462 cmpOp AddrGeOp = ALWAYS
2463 cmpOp AddrEqOp = EQQ
2465 cmpOp AddrLtOp = NEVER
2466 cmpOp AddrLeOp = EQQ
2468 genCondJump lbl (StPrim op [x, StDouble 0.0])
2469 = getRegister x `thenNat` \ register ->
2470 getNewRegNCG (registerRep register)
2473 code = registerCode register tmp
2474 value = registerName register tmp
2475 pk = registerRep register
2476 target = ImmCLbl lbl
2478 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2480 cmpOp FloatGtOp = GTT
2481 cmpOp FloatGeOp = GE
2482 cmpOp FloatEqOp = EQQ
2483 cmpOp FloatNeOp = NE
2484 cmpOp FloatLtOp = LTT
2485 cmpOp FloatLeOp = LE
2486 cmpOp DoubleGtOp = GTT
2487 cmpOp DoubleGeOp = GE
2488 cmpOp DoubleEqOp = EQQ
2489 cmpOp DoubleNeOp = NE
2490 cmpOp DoubleLtOp = LTT
2491 cmpOp DoubleLeOp = LE
2493 genCondJump lbl (StPrim op [x, y])
2495 = trivialFCode pr instr x y `thenNat` \ register ->
2496 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2498 code = registerCode register tmp
2499 result = registerName register tmp
2500 target = ImmCLbl lbl
2502 returnNat (code . mkSeqInstr (BF cond result target))
2504 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2506 fltCmpOp op = case op of
2520 (instr, cond) = case op of
2521 FloatGtOp -> (FCMP TF LE, EQQ)
2522 FloatGeOp -> (FCMP TF LTT, EQQ)
2523 FloatEqOp -> (FCMP TF EQQ, NE)
2524 FloatNeOp -> (FCMP TF EQQ, EQQ)
2525 FloatLtOp -> (FCMP TF LTT, NE)
2526 FloatLeOp -> (FCMP TF LE, NE)
2527 DoubleGtOp -> (FCMP TF LE, EQQ)
2528 DoubleGeOp -> (FCMP TF LTT, EQQ)
2529 DoubleEqOp -> (FCMP TF EQQ, NE)
2530 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2531 DoubleLtOp -> (FCMP TF LTT, NE)
2532 DoubleLeOp -> (FCMP TF LE, NE)
2534 genCondJump lbl (StPrim op [x, y])
2535 = trivialCode instr x y `thenNat` \ register ->
2536 getNewRegNCG IntRep `thenNat` \ tmp ->
2538 code = registerCode register tmp
2539 result = registerName register tmp
2540 target = ImmCLbl lbl
2542 returnNat (code . mkSeqInstr (BI cond result target))
2544 (instr, cond) = case op of
2545 CharGtOp -> (CMP LE, EQQ)
2546 CharGeOp -> (CMP LTT, EQQ)
2547 CharEqOp -> (CMP EQQ, NE)
2548 CharNeOp -> (CMP EQQ, EQQ)
2549 CharLtOp -> (CMP LTT, NE)
2550 CharLeOp -> (CMP LE, NE)
2551 IntGtOp -> (CMP LE, EQQ)
2552 IntGeOp -> (CMP LTT, EQQ)
2553 IntEqOp -> (CMP EQQ, NE)
2554 IntNeOp -> (CMP EQQ, EQQ)
2555 IntLtOp -> (CMP LTT, NE)
2556 IntLeOp -> (CMP LE, NE)
2557 WordGtOp -> (CMP ULE, EQQ)
2558 WordGeOp -> (CMP ULT, EQQ)
2559 WordEqOp -> (CMP EQQ, NE)
2560 WordNeOp -> (CMP EQQ, EQQ)
2561 WordLtOp -> (CMP ULT, NE)
2562 WordLeOp -> (CMP ULE, NE)
2563 AddrGtOp -> (CMP ULE, EQQ)
2564 AddrGeOp -> (CMP ULT, EQQ)
2565 AddrEqOp -> (CMP EQQ, NE)
2566 AddrNeOp -> (CMP EQQ, EQQ)
2567 AddrLtOp -> (CMP ULT, NE)
2568 AddrLeOp -> (CMP ULE, NE)
2570 #endif {- alpha_TARGET_ARCH -}
2572 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2574 #if i386_TARGET_ARCH
2576 genCondJump lbl bool
2577 = getCondCode bool `thenNat` \ condition ->
2579 code = condCode condition
2580 cond = condName condition
2582 returnNat (code `snocOL` JXX cond lbl)
2584 #endif {- i386_TARGET_ARCH -}
2586 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2588 #if sparc_TARGET_ARCH
2590 genCondJump lbl bool
2591 = getCondCode bool `thenNat` \ condition ->
2593 code = condCode condition
2594 cond = condName condition
2595 target = ImmCLbl lbl
2600 if condFloat condition
2601 then [NOP, BF cond False target, NOP]
2602 else [BI cond False target, NOP]
2606 #endif {- sparc_TARGET_ARCH -}
2608 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2611 %************************************************************************
2613 \subsection{Generating C calls}
2615 %************************************************************************
2617 Now the biggest nightmare---calls. Most of the nastiness is buried in
2618 @get_arg@, which moves the arguments to the correct registers/stack
2619 locations. Apart from that, the code is easy.
2621 (If applicable) Do not fill the delay slots here; you will confuse the
2626 :: FAST_STRING -- function to call
2628 -> PrimRep -- type of the result
2629 -> [StixExpr] -- arguments (of mixed type)
2632 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2634 #if alpha_TARGET_ARCH
2636 genCCall fn cconv kind args
2637 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2638 `thenNat` \ ((unused,_), argCode) ->
2640 nRegs = length allArgRegs - length unused
2641 code = asmSeqThen (map ($ []) argCode)
2644 LDA pv (AddrImm (ImmLab (ptext fn))),
2645 JSR ra (AddrReg pv) nRegs,
2646 LDGP gp (AddrReg ra)]
2648 ------------------------
2649 {- Try to get a value into a specific register (or registers) for
2650 a call. The first 6 arguments go into the appropriate
2651 argument register (separate registers for integer and floating
2652 point arguments, but used in lock-step), and the remaining
2653 arguments are dumped to the stack, beginning at 0(sp). Our
2654 first argument is a pair of the list of remaining argument
2655 registers to be assigned for this call and the next stack
2656 offset to use for overflowing arguments. This way,
2657 @get_Arg@ can be applied to all of a call's arguments using
2661 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2662 -> StixTree -- Current argument
2663 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2665 -- We have to use up all of our argument registers first...
2667 get_arg ((iDst,fDst):dsts, offset) arg
2668 = getRegister arg `thenNat` \ register ->
2670 reg = if isFloatingRep pk then fDst else iDst
2671 code = registerCode register reg
2672 src = registerName register reg
2673 pk = registerRep register
2676 if isFloatingRep pk then
2677 ((dsts, offset), if isFixed register then
2678 code . mkSeqInstr (FMOV src fDst)
2681 ((dsts, offset), if isFixed register then
2682 code . mkSeqInstr (OR src (RIReg src) iDst)
2685 -- Once we have run out of argument registers, we move to the
2688 get_arg ([], offset) arg
2689 = getRegister arg `thenNat` \ register ->
2690 getNewRegNCG (registerRep register)
2693 code = registerCode register tmp
2694 src = registerName register tmp
2695 pk = registerRep register
2696 sz = primRepToSize pk
2698 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2700 #endif {- alpha_TARGET_ARCH -}
2702 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2704 #if i386_TARGET_ARCH
2706 genCCall fn cconv ret_rep [StInt i]
2707 | fn == SLIT ("PerformGC_wrapper")
2709 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2710 CALL (ImmLit (ptext (if underscorePrefix
2711 then (SLIT ("_PerformGC_wrapper"))
2712 else (SLIT ("PerformGC_wrapper")))))
2718 genCCall fn cconv ret_rep args
2720 (reverse args) `thenNat` \ sizes_n_codes ->
2721 getDeltaNat `thenNat` \ delta ->
2722 let (sizes, codes) = unzip sizes_n_codes
2723 tot_arg_size = sum sizes
2724 code2 = concatOL codes
2726 [CALL (fn__2 tot_arg_size)]
2728 -- Deallocate parameters after call for ccall;
2729 -- but not for stdcall (callee does it)
2730 (if cconv == StdCallConv then [] else
2731 [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2734 [DELTA (delta + tot_arg_size)]
2737 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2738 returnNat (code2 `appOL` call)
2741 -- function names that begin with '.' are assumed to be special
2742 -- internally generated names like '.mul,' which don't get an
2743 -- underscore prefix
2744 -- ToDo:needed (WDP 96/03) ???
2748 = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
2749 | otherwise -- General case
2750 = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
2752 stdcallsize tot_arg_size
2753 | cconv == StdCallConv = '@':show tot_arg_size
2761 push_arg :: StixExpr{-current argument-}
2762 -> NatM (Int, InstrBlock) -- argsz, code
2765 | is64BitRep arg_rep
2766 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2767 getDeltaNat `thenNat` \ delta ->
2768 setDeltaNat (delta - 8) `thenNat` \ _ ->
2769 let r_lo = VirtualRegI vr_lo
2770 r_hi = getHiVRegFromLo r_lo
2773 toOL [PUSH L (OpReg r_hi), DELTA (delta - 4),
2774 PUSH L (OpReg r_lo), DELTA (delta - 8)]
2777 = get_op arg `thenNat` \ (code, reg, sz) ->
2778 getDeltaNat `thenNat` \ delta ->
2779 arg_size sz `bind` \ size ->
2780 setDeltaNat (delta-size) `thenNat` \ _ ->
2781 if (case sz of DF -> True; F -> True; _ -> False)
2782 then returnNat (size,
2784 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2786 GST sz reg (AddrBaseIndex (Just esp)
2790 else returnNat (size,
2792 PUSH L (OpReg reg) `snocOL`
2796 arg_rep = repOfStixExpr arg
2801 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2804 = getRegister op `thenNat` \ register ->
2805 getNewRegNCG (registerRep register)
2808 code = registerCode register tmp
2809 reg = registerName register tmp
2810 pk = registerRep register
2811 sz = primRepToSize pk
2813 returnNat (code, reg, sz)
2815 #endif {- i386_TARGET_ARCH -}
2817 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2819 #if sparc_TARGET_ARCH
2821 The SPARC calling convention is an absolute
2822 nightmare. The first 6x32 bits of arguments are mapped into
2823 %o0 through %o5, and the remaining arguments are dumped to the
2824 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
2826 If we have to put args on the stack, move %o6==%sp down by
2827 the number of words to go on the stack, to ensure there's enough space.
2829 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
2830 16 words above the stack pointer is a word for the address of
2831 a structure return value. I use this as a temporary location
2832 for moving values from float to int regs. Certainly it isn't
2833 safe to put anything in the 16 words starting at %sp, since
2834 this area can get trashed at any time due to window overflows
2835 caused by signal handlers.
2837 A final complication (if the above isn't enough) is that
2838 we can't blithely calculate the arguments one by one into
2839 %o0 .. %o5. Consider the following nested calls:
2843 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
2844 the inner call will itself use %o0, which trashes the value put there
2845 in preparation for the outer call. Upshot: we need to calculate the
2846 args into temporary regs, and move those to arg regs or onto the
2847 stack only immediately prior to the call proper. Sigh.
2850 genCCall fn cconv kind args
2851 = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
2852 let (argcodes, vregss) = unzip argcode_and_vregs
2853 argcode = concatOL argcodes
2854 vregs = concat vregss
2855 n_argRegs = length allArgRegs
2856 n_argRegs_used = min (length vregs) n_argRegs
2857 (move_sp_down, move_sp_up)
2858 = let nn = length vregs - n_argRegs
2859 + 1 -- (for the road)
2862 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
2864 = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
2866 = unitOL (CALL fn__2 n_argRegs_used False)
2868 returnNat (argcode `appOL`
2869 move_sp_down `appOL`
2870 transfer_code `appOL`
2875 -- function names that begin with '.' are assumed to be special
2876 -- internally generated names like '.mul,' which don't get an
2877 -- underscore prefix
2878 -- ToDo:needed (WDP 96/03) ???
2879 fn__2 = case (_HEAD_ fn) of
2880 '.' -> ImmLit (ptext fn)
2881 _ -> ImmLab False (ptext fn)
2883 -- move args from the integer vregs into which they have been
2884 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
2885 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
2887 move_final [] _ offset -- all args done
2890 move_final (v:vs) [] offset -- out of aregs; move to stack
2891 = ST W v (spRel offset)
2892 : move_final vs [] (offset+1)
2894 move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
2895 = OR False g0 (RIReg v) a
2896 : move_final vs az offset
2898 -- generate code to calculate an argument, and move it into one
2899 -- or two integer vregs.
2900 arg_to_int_vregs :: StixExpr -> NatM (OrdList Instr, [Reg])
2901 arg_to_int_vregs arg
2902 | is64BitRep (repOfStixExpr arg)
2903 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2904 let r_lo = VirtualRegI vr_lo
2905 r_hi = getHiVRegFromLo r_lo
2906 in returnNat (code, [r_hi, r_lo])
2908 = getRegister arg `thenNat` \ register ->
2909 getNewRegNCG (registerRep register) `thenNat` \ tmp ->
2910 let code = registerCode register tmp
2911 src = registerName register tmp
2912 pk = registerRep register
2914 -- the value is in src. Get it into 1 or 2 int vregs.
2917 getNewRegNCG WordRep `thenNat` \ v1 ->
2918 getNewRegNCG WordRep `thenNat` \ v2 ->
2921 FMOV DF src f0 `snocOL`
2922 ST F f0 (spRel 16) `snocOL`
2923 LD W (spRel 16) v1 `snocOL`
2924 ST F (fPair f0) (spRel 16) `snocOL`
2930 getNewRegNCG WordRep `thenNat` \ v1 ->
2933 ST F src (spRel 16) `snocOL`
2939 getNewRegNCG WordRep `thenNat` \ v1 ->
2941 code `snocOL` OR False g0 (RIReg src) v1
2945 #endif {- sparc_TARGET_ARCH -}
2947 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2950 %************************************************************************
2952 \subsection{Support bits}
2954 %************************************************************************
2956 %************************************************************************
2958 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2960 %************************************************************************
2962 Turn those condition codes into integers now (when they appear on
2963 the right hand side of an assignment).
2965 (If applicable) Do not fill the delay slots here; you will confuse the
2969 condIntReg, condFltReg :: Cond -> StixExpr -> StixExpr -> NatM Register
2971 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2973 #if alpha_TARGET_ARCH
2974 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2975 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2976 #endif {- alpha_TARGET_ARCH -}
2978 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2980 #if i386_TARGET_ARCH
2983 = condIntCode cond x y `thenNat` \ condition ->
2984 getNewRegNCG IntRep `thenNat` \ tmp ->
2986 code = condCode condition
2987 cond = condName condition
2988 code__2 dst = code `appOL` toOL [
2989 SETCC cond (OpReg tmp),
2990 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2991 MOV L (OpReg tmp) (OpReg dst)]
2993 returnNat (Any IntRep code__2)
2996 = getNatLabelNCG `thenNat` \ lbl1 ->
2997 getNatLabelNCG `thenNat` \ lbl2 ->
2998 condFltCode cond x y `thenNat` \ condition ->
3000 code = condCode condition
3001 cond = condName condition
3002 code__2 dst = code `appOL` toOL [
3004 MOV L (OpImm (ImmInt 0)) (OpReg dst),
3007 MOV L (OpImm (ImmInt 1)) (OpReg dst),
3010 returnNat (Any IntRep code__2)
3012 #endif {- i386_TARGET_ARCH -}
3014 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3016 #if sparc_TARGET_ARCH
3018 condIntReg EQQ x (StInt 0)
3019 = getRegister x `thenNat` \ register ->
3020 getNewRegNCG IntRep `thenNat` \ tmp ->
3022 code = registerCode register tmp
3023 src = registerName register tmp
3024 code__2 dst = code `appOL` toOL [
3025 SUB False True g0 (RIReg src) g0,
3026 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3028 returnNat (Any IntRep code__2)
3031 = getRegister x `thenNat` \ register1 ->
3032 getRegister y `thenNat` \ register2 ->
3033 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3034 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3036 code1 = registerCode register1 tmp1
3037 src1 = registerName register1 tmp1
3038 code2 = registerCode register2 tmp2
3039 src2 = registerName register2 tmp2
3040 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3041 XOR False src1 (RIReg src2) dst,
3042 SUB False True g0 (RIReg dst) g0,
3043 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3045 returnNat (Any IntRep code__2)
3047 condIntReg NE x (StInt 0)
3048 = getRegister x `thenNat` \ register ->
3049 getNewRegNCG IntRep `thenNat` \ tmp ->
3051 code = registerCode register tmp
3052 src = registerName register tmp
3053 code__2 dst = code `appOL` toOL [
3054 SUB False True g0 (RIReg src) g0,
3055 ADD True False g0 (RIImm (ImmInt 0)) dst]
3057 returnNat (Any IntRep code__2)
3060 = getRegister x `thenNat` \ register1 ->
3061 getRegister y `thenNat` \ register2 ->
3062 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3063 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3065 code1 = registerCode register1 tmp1
3066 src1 = registerName register1 tmp1
3067 code2 = registerCode register2 tmp2
3068 src2 = registerName register2 tmp2
3069 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3070 XOR False src1 (RIReg src2) dst,
3071 SUB False True g0 (RIReg dst) g0,
3072 ADD True False g0 (RIImm (ImmInt 0)) dst]
3074 returnNat (Any IntRep code__2)
3077 = getNatLabelNCG `thenNat` \ lbl1 ->
3078 getNatLabelNCG `thenNat` \ lbl2 ->
3079 condIntCode cond x y `thenNat` \ condition ->
3081 code = condCode condition
3082 cond = condName condition
3083 code__2 dst = code `appOL` toOL [
3084 BI cond False (ImmCLbl lbl1), NOP,
3085 OR False g0 (RIImm (ImmInt 0)) dst,
3086 BI ALWAYS False (ImmCLbl lbl2), NOP,
3088 OR False g0 (RIImm (ImmInt 1)) dst,
3091 returnNat (Any IntRep code__2)
3094 = getNatLabelNCG `thenNat` \ lbl1 ->
3095 getNatLabelNCG `thenNat` \ lbl2 ->
3096 condFltCode cond x y `thenNat` \ condition ->
3098 code = condCode condition
3099 cond = condName condition
3100 code__2 dst = code `appOL` toOL [
3102 BF cond False (ImmCLbl lbl1), NOP,
3103 OR False g0 (RIImm (ImmInt 0)) dst,
3104 BI ALWAYS False (ImmCLbl lbl2), NOP,
3106 OR False g0 (RIImm (ImmInt 1)) dst,
3109 returnNat (Any IntRep code__2)
3111 #endif {- sparc_TARGET_ARCH -}
3113 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3116 %************************************************************************
3118 \subsubsection{@trivial*Code@: deal with trivial instructions}
3120 %************************************************************************
3122 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
3123 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
3124 for constants on the right hand side, because that's where the generic
3125 optimizer will have put them.
3127 Similarly, for unary instructions, we don't have to worry about
3128 matching an StInt as the argument, because genericOpt will already
3129 have handled the constant-folding.
3133 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
3134 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
3135 -> Maybe (Operand -> Operand -> Instr)
3136 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
3138 -> StixExpr -> StixExpr -- the two arguments
3143 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
3144 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
3145 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
3147 -> StixExpr -> StixExpr -- the two arguments
3151 :: IF_ARCH_alpha((RI -> Reg -> Instr)
3152 ,IF_ARCH_i386 ((Operand -> Instr)
3153 ,IF_ARCH_sparc((RI -> Reg -> Instr)
3155 -> StixExpr -- the one argument
3160 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
3161 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
3162 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
3164 -> StixExpr -- the one argument
3167 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3169 #if alpha_TARGET_ARCH
3171 trivialCode instr x (StInt y)
3173 = getRegister x `thenNat` \ register ->
3174 getNewRegNCG IntRep `thenNat` \ tmp ->
3176 code = registerCode register tmp
3177 src1 = registerName register tmp
3178 src2 = ImmInt (fromInteger y)
3179 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
3181 returnNat (Any IntRep code__2)
3183 trivialCode instr x y
3184 = getRegister x `thenNat` \ register1 ->
3185 getRegister y `thenNat` \ register2 ->
3186 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3187 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3189 code1 = registerCode register1 tmp1 []
3190 src1 = registerName register1 tmp1
3191 code2 = registerCode register2 tmp2 []
3192 src2 = registerName register2 tmp2
3193 code__2 dst = asmSeqThen [code1, code2] .
3194 mkSeqInstr (instr src1 (RIReg src2) dst)
3196 returnNat (Any IntRep code__2)
3199 trivialUCode instr x
3200 = getRegister x `thenNat` \ register ->
3201 getNewRegNCG IntRep `thenNat` \ tmp ->
3203 code = registerCode register tmp
3204 src = registerName register tmp
3205 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3207 returnNat (Any IntRep code__2)
3210 trivialFCode _ instr x y
3211 = getRegister x `thenNat` \ register1 ->
3212 getRegister y `thenNat` \ register2 ->
3213 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3214 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3216 code1 = registerCode register1 tmp1
3217 src1 = registerName register1 tmp1
3219 code2 = registerCode register2 tmp2
3220 src2 = registerName register2 tmp2
3222 code__2 dst = asmSeqThen [code1 [], code2 []] .
3223 mkSeqInstr (instr src1 src2 dst)
3225 returnNat (Any DoubleRep code__2)
3227 trivialUFCode _ instr x
3228 = getRegister x `thenNat` \ register ->
3229 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3231 code = registerCode register tmp
3232 src = registerName register tmp
3233 code__2 dst = code . mkSeqInstr (instr src dst)
3235 returnNat (Any DoubleRep code__2)
3237 #endif {- alpha_TARGET_ARCH -}
3239 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3241 #if i386_TARGET_ARCH
3243 The Rules of the Game are:
3245 * You cannot assume anything about the destination register dst;
3246 it may be anything, including a fixed reg.
3248 * You may compute an operand into a fixed reg, but you may not
3249 subsequently change the contents of that fixed reg. If you
3250 want to do so, first copy the value either to a temporary
3251 or into dst. You are free to modify dst even if it happens
3252 to be a fixed reg -- that's not your problem.
3254 * You cannot assume that a fixed reg will stay live over an
3255 arbitrary computation. The same applies to the dst reg.
3257 * Temporary regs obtained from getNewRegNCG are distinct from
3258 each other and from all other regs, and stay live over
3259 arbitrary computations.
3263 trivialCode instr maybe_revinstr a b
3266 = getRegister a `thenNat` \ rega ->
3269 then registerCode rega dst `bind` \ code_a ->
3271 instr (OpImm imm_b) (OpReg dst)
3272 else registerCodeF rega `bind` \ code_a ->
3273 registerNameF rega `bind` \ r_a ->
3275 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3276 instr (OpImm imm_b) (OpReg dst)
3278 returnNat (Any IntRep mkcode)
3281 = getRegister b `thenNat` \ regb ->
3282 getNewRegNCG IntRep `thenNat` \ tmp ->
3283 let revinstr_avail = maybeToBool maybe_revinstr
3284 revinstr = case maybe_revinstr of Just ri -> ri
3288 then registerCode regb dst `bind` \ code_b ->
3290 revinstr (OpImm imm_a) (OpReg dst)
3291 else registerCodeF regb `bind` \ code_b ->
3292 registerNameF regb `bind` \ r_b ->
3294 MOV L (OpReg r_b) (OpReg dst) `snocOL`
3295 revinstr (OpImm imm_a) (OpReg dst)
3299 then registerCode regb tmp `bind` \ code_b ->
3301 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3302 instr (OpReg tmp) (OpReg dst)
3303 else registerCodeF regb `bind` \ code_b ->
3304 registerNameF regb `bind` \ r_b ->
3306 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
3307 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3308 instr (OpReg tmp) (OpReg dst)
3310 returnNat (Any IntRep mkcode)
3313 = getRegister a `thenNat` \ rega ->
3314 getRegister b `thenNat` \ regb ->
3315 getNewRegNCG IntRep `thenNat` \ tmp ->
3317 = case (isAny rega, isAny regb) of
3319 -> registerCode regb tmp `bind` \ code_b ->
3320 registerCode rega dst `bind` \ code_a ->
3323 instr (OpReg tmp) (OpReg dst)
3325 -> registerCode rega tmp `bind` \ code_a ->
3326 registerCodeF regb `bind` \ code_b ->
3327 registerNameF regb `bind` \ r_b ->
3330 instr (OpReg r_b) (OpReg tmp) `snocOL`
3331 MOV L (OpReg tmp) (OpReg dst)
3333 -> registerCode regb tmp `bind` \ code_b ->
3334 registerCodeF rega `bind` \ code_a ->
3335 registerNameF rega `bind` \ r_a ->
3338 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3339 instr (OpReg tmp) (OpReg dst)
3341 -> registerCodeF rega `bind` \ code_a ->
3342 registerNameF rega `bind` \ r_a ->
3343 registerCodeF regb `bind` \ code_b ->
3344 registerNameF regb `bind` \ r_b ->
3346 MOV L (OpReg r_a) (OpReg tmp) `appOL`
3348 instr (OpReg r_b) (OpReg tmp) `snocOL`
3349 MOV L (OpReg tmp) (OpReg dst)
3351 returnNat (Any IntRep mkcode)
3354 maybe_imm_a = maybeImm a
3355 is_imm_a = maybeToBool maybe_imm_a
3356 imm_a = case maybe_imm_a of Just imm -> imm
3358 maybe_imm_b = maybeImm b
3359 is_imm_b = maybeToBool maybe_imm_b
3360 imm_b = case maybe_imm_b of Just imm -> imm
3364 trivialUCode instr x
3365 = getRegister x `thenNat` \ register ->
3367 code__2 dst = let code = registerCode register dst
3368 src = registerName register dst
3370 if isFixed register && dst /= src
3371 then toOL [MOV L (OpReg src) (OpReg dst),
3373 else unitOL (instr (OpReg src))
3375 returnNat (Any IntRep code__2)
3378 trivialFCode pk instr x y
3379 = getRegister x `thenNat` \ register1 ->
3380 getRegister y `thenNat` \ register2 ->
3381 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3382 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3384 code1 = registerCode register1 tmp1
3385 src1 = registerName register1 tmp1
3387 code2 = registerCode register2 tmp2
3388 src2 = registerName register2 tmp2
3391 -- treat the common case specially: both operands in
3393 | isAny register1 && isAny register2
3396 instr (primRepToSize pk) src1 src2 dst
3398 -- be paranoid (and inefficient)
3400 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3402 instr (primRepToSize pk) tmp1 src2 dst
3404 returnNat (Any pk code__2)
3408 trivialUFCode pk instr x
3409 = getRegister x `thenNat` \ register ->
3410 getNewRegNCG pk `thenNat` \ tmp ->
3412 code = registerCode register tmp
3413 src = registerName register tmp
3414 code__2 dst = code `snocOL` instr src dst
3416 returnNat (Any pk code__2)
3418 #endif {- i386_TARGET_ARCH -}
3420 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3422 #if sparc_TARGET_ARCH
3424 trivialCode instr x (StInt y)
3426 = getRegister x `thenNat` \ register ->
3427 getNewRegNCG IntRep `thenNat` \ tmp ->
3429 code = registerCode register tmp
3430 src1 = registerName register tmp
3431 src2 = ImmInt (fromInteger y)
3432 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3434 returnNat (Any IntRep code__2)
3436 trivialCode instr x y
3437 = getRegister x `thenNat` \ register1 ->
3438 getRegister y `thenNat` \ register2 ->
3439 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3440 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3442 code1 = registerCode register1 tmp1
3443 src1 = registerName register1 tmp1
3444 code2 = registerCode register2 tmp2
3445 src2 = registerName register2 tmp2
3446 code__2 dst = code1 `appOL` code2 `snocOL`
3447 instr src1 (RIReg src2) dst
3449 returnNat (Any IntRep code__2)
3452 trivialFCode pk instr x y
3453 = getRegister x `thenNat` \ register1 ->
3454 getRegister y `thenNat` \ register2 ->
3455 getNewRegNCG (registerRep register1)
3457 getNewRegNCG (registerRep register2)
3459 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3461 promote x = FxTOy F DF x tmp
3463 pk1 = registerRep register1
3464 code1 = registerCode register1 tmp1
3465 src1 = registerName register1 tmp1
3467 pk2 = registerRep register2
3468 code2 = registerCode register2 tmp2
3469 src2 = registerName register2 tmp2
3473 code1 `appOL` code2 `snocOL`
3474 instr (primRepToSize pk) src1 src2 dst
3475 else if pk1 == FloatRep then
3476 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3477 instr DF tmp src2 dst
3479 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3480 instr DF src1 tmp dst
3482 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3485 trivialUCode instr x
3486 = getRegister x `thenNat` \ register ->
3487 getNewRegNCG IntRep `thenNat` \ tmp ->
3489 code = registerCode register tmp
3490 src = registerName register tmp
3491 code__2 dst = code `snocOL` instr (RIReg src) dst
3493 returnNat (Any IntRep code__2)
3496 trivialUFCode pk instr x
3497 = getRegister x `thenNat` \ register ->
3498 getNewRegNCG pk `thenNat` \ tmp ->
3500 code = registerCode register tmp
3501 src = registerName register tmp
3502 code__2 dst = code `snocOL` instr src dst
3504 returnNat (Any pk code__2)
3506 #endif {- sparc_TARGET_ARCH -}
3508 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3511 %************************************************************************
3513 \subsubsection{Coercing to/from integer/floating-point...}
3515 %************************************************************************
3517 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3518 conversions. We have to store temporaries in memory to move
3519 between the integer and the floating point register sets.
3521 @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
3522 pretend, on sparc at least, that double and float regs are seperate
3523 kinds, so the value has to be computed into one kind before being
3524 explicitly "converted" to live in the other kind.
3527 coerceInt2FP :: PrimRep -> StixExpr -> NatM Register
3528 coerceFP2Int :: PrimRep -> StixExpr -> NatM Register
3530 coerceDbl2Flt :: StixExpr -> NatM Register
3531 coerceFlt2Dbl :: StixExpr -> NatM Register
3535 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3537 #if alpha_TARGET_ARCH
3540 = getRegister x `thenNat` \ register ->
3541 getNewRegNCG IntRep `thenNat` \ reg ->
3543 code = registerCode register reg
3544 src = registerName register reg
3546 code__2 dst = code . mkSeqInstrs [
3548 LD TF dst (spRel 0),
3551 returnNat (Any DoubleRep code__2)
3555 = getRegister x `thenNat` \ register ->
3556 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3558 code = registerCode register tmp
3559 src = registerName register tmp
3561 code__2 dst = code . mkSeqInstrs [
3563 ST TF tmp (spRel 0),
3566 returnNat (Any IntRep code__2)
3568 #endif {- alpha_TARGET_ARCH -}
3570 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3572 #if i386_TARGET_ARCH
3575 = getRegister x `thenNat` \ register ->
3576 getNewRegNCG IntRep `thenNat` \ reg ->
3578 code = registerCode register reg
3579 src = registerName register reg
3580 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3581 code__2 dst = code `snocOL` opc src dst
3583 returnNat (Any pk code__2)
3586 coerceFP2Int fprep x
3587 = getRegister x `thenNat` \ register ->
3588 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3590 code = registerCode register tmp
3591 src = registerName register tmp
3592 pk = registerRep register
3594 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3595 code__2 dst = code `snocOL` opc src dst
3597 returnNat (Any IntRep code__2)
3600 coerceDbl2Flt x = panic "MachCode.coerceDbl2Flt: unused on x86"
3601 coerceFlt2Dbl x = panic "MachCode.coerceFlt2Dbl: unused on x86"
3603 #endif {- i386_TARGET_ARCH -}
3605 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3607 #if sparc_TARGET_ARCH
3610 = getRegister x `thenNat` \ register ->
3611 getNewRegNCG IntRep `thenNat` \ reg ->
3613 code = registerCode register reg
3614 src = registerName register reg
3616 code__2 dst = code `appOL` toOL [
3617 ST W src (spRel (-2)),
3618 LD W (spRel (-2)) dst,
3619 FxTOy W (primRepToSize pk) dst dst]
3621 returnNat (Any pk code__2)
3624 coerceFP2Int fprep x
3625 = ASSERT(fprep == DoubleRep || fprep == FloatRep)
3626 getRegister x `thenNat` \ register ->
3627 getNewRegNCG fprep `thenNat` \ reg ->
3628 getNewRegNCG FloatRep `thenNat` \ tmp ->
3630 code = registerCode register reg
3631 src = registerName register reg
3632 code__2 dst = code `appOL` toOL [
3633 FxTOy (primRepToSize fprep) W src tmp,
3634 ST W tmp (spRel (-2)),
3635 LD W (spRel (-2)) dst]
3637 returnNat (Any IntRep code__2)
3641 = getRegister x `thenNat` \ register ->
3642 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3643 let code = registerCode register tmp
3644 src = registerName register tmp
3646 returnNat (Any FloatRep
3647 (\dst -> code `snocOL` FxTOy DF F src dst))
3651 = getRegister x `thenNat` \ register ->
3652 getNewRegNCG FloatRep `thenNat` \ tmp ->
3653 let code = registerCode register tmp
3654 src = registerName register tmp
3656 returnNat (Any DoubleRep
3657 (\dst -> code `snocOL` FxTOy F DF src dst))
3659 #endif {- sparc_TARGET_ARCH -}
3661 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -