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
1016 code dst = code1 `appOL` code2 `appOL`
1018 MOV L (OpReg src1) (OpReg res_hi),
1019 MOV L (OpReg src2) (OpReg res_lo),
1020 IMUL64 res_hi res_lo, -- result in res_hi:res_lo
1021 SAR L (ImmInt 31) (OpReg res_lo), -- sign extend lower part
1022 SUB L (OpReg res_hi) (OpReg res_lo), -- compare against upper
1023 MOV L (OpReg res_lo) (OpReg dst)
1024 -- dst==0 if high part == sign extended low part
1027 returnNat (Any IntRep code)
1029 --------------------
1030 shift_code :: (Imm -> Operand -> Instr)
1035 {- Case1: shift length as immediate -}
1036 -- Code is the same as the first eq. for trivialCode -- sigh.
1037 shift_code instr x y{-amount-}
1039 = getRegister x `thenNat` \ regx ->
1042 then registerCodeA regx dst `bind` \ code_x ->
1044 instr imm__2 (OpReg dst)
1045 else registerCodeF regx `bind` \ code_x ->
1046 registerNameF regx `bind` \ r_x ->
1048 MOV L (OpReg r_x) (OpReg dst) `snocOL`
1049 instr imm__2 (OpReg dst)
1051 returnNat (Any IntRep mkcode)
1054 imm__2 = case imm of Just x -> x
1056 {- Case2: shift length is complex (non-immediate) -}
1057 -- Since ECX is always used as a spill temporary, we can't
1058 -- use it here to do non-immediate shifts. No big deal --
1059 -- they are only very rare, and we can use an equivalent
1060 -- test-and-jump sequence which doesn't use ECX.
1061 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
1062 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
1063 shift_code instr x y{-amount-}
1064 = getRegister x `thenNat` \ register1 ->
1065 getRegister y `thenNat` \ register2 ->
1066 getNatLabelNCG `thenNat` \ lbl_test3 ->
1067 getNatLabelNCG `thenNat` \ lbl_test2 ->
1068 getNatLabelNCG `thenNat` \ lbl_test1 ->
1069 getNatLabelNCG `thenNat` \ lbl_test0 ->
1070 getNatLabelNCG `thenNat` \ lbl_after ->
1071 getNewRegNCG IntRep `thenNat` \ tmp ->
1073 = let src_val = registerName register1 dst
1074 code_val = registerCode register1 dst
1075 src_amt = registerName register2 tmp
1076 code_amt = registerCode register2 tmp
1081 MOV L (OpReg src_amt) r_tmp `appOL`
1083 MOV L (OpReg src_val) r_dst `appOL`
1085 COMMENT (_PK_ "begin shift sequence"),
1086 MOV L (OpReg src_val) r_dst,
1087 MOV L (OpReg src_amt) r_tmp,
1089 BT L (ImmInt 4) r_tmp,
1091 instr (ImmInt 16) r_dst,
1094 BT L (ImmInt 3) r_tmp,
1096 instr (ImmInt 8) r_dst,
1099 BT L (ImmInt 2) r_tmp,
1101 instr (ImmInt 4) r_dst,
1104 BT L (ImmInt 1) r_tmp,
1106 instr (ImmInt 2) r_dst,
1109 BT L (ImmInt 0) r_tmp,
1111 instr (ImmInt 1) r_dst,
1114 COMMENT (_PK_ "end shift sequence")
1117 returnNat (Any IntRep code__2)
1119 --------------------
1120 add_code :: Size -> StixExpr -> StixExpr -> NatM Register
1122 add_code sz x (StInt y)
1123 = getRegister x `thenNat` \ register ->
1124 getNewRegNCG IntRep `thenNat` \ tmp ->
1126 code = registerCode register tmp
1127 src1 = registerName register tmp
1128 src2 = ImmInt (fromInteger y)
1131 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1134 returnNat (Any IntRep code__2)
1136 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
1138 --------------------
1139 sub_code :: Size -> StixExpr -> StixExpr -> NatM Register
1141 sub_code sz x (StInt y)
1142 = getRegister x `thenNat` \ register ->
1143 getNewRegNCG IntRep `thenNat` \ tmp ->
1145 code = registerCode register tmp
1146 src1 = registerName register tmp
1147 src2 = ImmInt (-(fromInteger y))
1150 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1153 returnNat (Any IntRep code__2)
1155 sub_code sz x y = trivialCode (SUB sz) Nothing x y
1157 getRegister (StInd pk mem)
1158 | not (is64BitRep pk)
1159 = getAmode mem `thenNat` \ amode ->
1161 code = amodeCode amode
1162 src = amodeAddr amode
1163 size = primRepToSize pk
1164 code__2 dst = code `snocOL`
1165 if pk == DoubleRep || pk == FloatRep
1166 then GLD size src dst
1174 (OpAddr src) (OpReg dst)
1176 returnNat (Any pk code__2)
1178 getRegister (StInt i)
1180 src = ImmInt (fromInteger i)
1183 = unitOL (XOR L (OpReg dst) (OpReg dst))
1185 = unitOL (MOV L (OpImm src) (OpReg dst))
1187 returnNat (Any IntRep code)
1191 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
1193 returnNat (Any PtrRep code)
1195 = ncgPrimopMoan "getRegister(x86)" (pprStixExpr leaf)
1198 imm__2 = case imm of Just x -> x
1200 #endif {- i386_TARGET_ARCH -}
1202 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1204 #if sparc_TARGET_ARCH
1206 getRegister (StFloat d)
1207 = getNatLabelNCG `thenNat` \ lbl ->
1208 getNewRegNCG PtrRep `thenNat` \ tmp ->
1209 let code dst = toOL [
1210 SEGMENT DataSegment,
1212 DATA F [ImmFloat d],
1213 SEGMENT TextSegment,
1214 SETHI (HI (ImmCLbl lbl)) tmp,
1215 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1217 returnNat (Any FloatRep code)
1219 getRegister (StDouble d)
1220 = getNatLabelNCG `thenNat` \ lbl ->
1221 getNewRegNCG PtrRep `thenNat` \ tmp ->
1222 let code dst = toOL [
1223 SEGMENT DataSegment,
1225 DATA DF [ImmDouble d],
1226 SEGMENT TextSegment,
1227 SETHI (HI (ImmCLbl lbl)) tmp,
1228 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1230 returnNat (Any DoubleRep code)
1233 getRegister (StMachOp mop [x]) -- unary PrimOps
1235 MO_NatS_Neg -> trivialUCode (SUB False False g0) x
1236 MO_Nat_Not -> trivialUCode (XNOR False g0) x
1238 MO_Flt_Neg -> trivialUFCode FloatRep (FNEG F) x
1239 MO_Dbl_Neg -> trivialUFCode DoubleRep (FNEG DF) x
1241 MO_Dbl_to_Flt -> coerceDbl2Flt x
1242 MO_Flt_to_Dbl -> coerceFlt2Dbl x
1244 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
1245 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
1246 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
1247 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
1249 -- Conversions which are a nop on sparc
1250 MO_32U_to_NatS -> conversionNop IntRep x
1251 MO_NatS_to_32U -> conversionNop WordRep x
1253 MO_NatU_to_NatS -> conversionNop IntRep x
1254 MO_NatS_to_NatU -> conversionNop WordRep x
1255 MO_NatP_to_NatU -> conversionNop WordRep x
1256 MO_NatU_to_NatP -> conversionNop PtrRep x
1257 MO_NatS_to_NatP -> conversionNop PtrRep x
1258 MO_NatP_to_NatS -> conversionNop IntRep x
1260 -- sign-extending widenings
1261 MO_8U_to_NatU -> integerExtend False 24 x
1262 MO_8S_to_NatS -> integerExtend True 24 x
1263 MO_16U_to_NatU -> integerExtend False 16 x
1264 MO_16S_to_NatS -> integerExtend True 16 x
1267 let fixed_x = if is_float_op -- promote to double
1268 then StMachOp MO_Flt_to_Dbl [x]
1271 getRegister (StCall fn CCallConv DoubleRep [fixed_x])
1273 integerExtend signed nBits x
1275 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
1276 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
1278 conversionNop new_rep expr
1279 = getRegister expr `thenNat` \ e_code ->
1280 returnNat (swizzleRegisterRep e_code new_rep)
1284 MO_Flt_Exp -> (True, SLIT("exp"))
1285 MO_Flt_Log -> (True, SLIT("log"))
1286 MO_Flt_Sqrt -> (True, SLIT("sqrt"))
1288 MO_Flt_Sin -> (True, SLIT("sin"))
1289 MO_Flt_Cos -> (True, SLIT("cos"))
1290 MO_Flt_Tan -> (True, SLIT("tan"))
1292 MO_Flt_Asin -> (True, SLIT("asin"))
1293 MO_Flt_Acos -> (True, SLIT("acos"))
1294 MO_Flt_Atan -> (True, SLIT("atan"))
1296 MO_Flt_Sinh -> (True, SLIT("sinh"))
1297 MO_Flt_Cosh -> (True, SLIT("cosh"))
1298 MO_Flt_Tanh -> (True, SLIT("tanh"))
1300 MO_Dbl_Exp -> (False, SLIT("exp"))
1301 MO_Dbl_Log -> (False, SLIT("log"))
1302 MO_Dbl_Sqrt -> (False, SLIT("sqrt"))
1304 MO_Dbl_Sin -> (False, SLIT("sin"))
1305 MO_Dbl_Cos -> (False, SLIT("cos"))
1306 MO_Dbl_Tan -> (False, SLIT("tan"))
1308 MO_Dbl_Asin -> (False, SLIT("asin"))
1309 MO_Dbl_Acos -> (False, SLIT("acos"))
1310 MO_Dbl_Atan -> (False, SLIT("atan"))
1312 MO_Dbl_Sinh -> (False, SLIT("sinh"))
1313 MO_Dbl_Cosh -> (False, SLIT("cosh"))
1314 MO_Dbl_Tanh -> (False, SLIT("tanh"))
1316 other -> pprPanic "getRegister(sparc) - binary StMachOp (2)"
1320 getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
1322 MO_32U_Gt -> condIntReg GTT x y
1323 MO_32U_Ge -> condIntReg GE x y
1324 MO_32U_Eq -> condIntReg EQQ x y
1325 MO_32U_Ne -> condIntReg NE x y
1326 MO_32U_Lt -> condIntReg LTT x y
1327 MO_32U_Le -> condIntReg LE x y
1329 MO_Nat_Eq -> condIntReg EQQ x y
1330 MO_Nat_Ne -> condIntReg NE x y
1332 MO_NatS_Gt -> condIntReg GTT x y
1333 MO_NatS_Ge -> condIntReg GE x y
1334 MO_NatS_Lt -> condIntReg LTT x y
1335 MO_NatS_Le -> condIntReg LE x y
1337 MO_NatU_Gt -> condIntReg GU x y
1338 MO_NatU_Ge -> condIntReg GEU x y
1339 MO_NatU_Lt -> condIntReg LU x y
1340 MO_NatU_Le -> condIntReg LEU x y
1342 MO_Flt_Gt -> condFltReg GTT x y
1343 MO_Flt_Ge -> condFltReg GE x y
1344 MO_Flt_Eq -> condFltReg EQQ x y
1345 MO_Flt_Ne -> condFltReg NE x y
1346 MO_Flt_Lt -> condFltReg LTT x y
1347 MO_Flt_Le -> condFltReg LE x y
1349 MO_Dbl_Gt -> condFltReg GTT x y
1350 MO_Dbl_Ge -> condFltReg GE x y
1351 MO_Dbl_Eq -> condFltReg EQQ x y
1352 MO_Dbl_Ne -> condFltReg NE x y
1353 MO_Dbl_Lt -> condFltReg LTT x y
1354 MO_Dbl_Le -> condFltReg LE x y
1356 MO_Nat_Add -> trivialCode (ADD False False) x y
1357 MO_Nat_Sub -> trivialCode (SUB False False) x y
1359 MO_NatS_Mul -> trivialCode (SMUL False) x y
1360 MO_NatU_Mul -> trivialCode (UMUL False) x y
1361 MO_NatS_MulMayOflo -> imulMayOflo x y
1363 -- ToDo: teach about V8+ SPARC div instructions
1364 MO_NatS_Quot -> idiv SLIT(".div") x y
1365 MO_NatS_Rem -> idiv SLIT(".rem") x y
1366 MO_NatU_Quot -> idiv SLIT(".udiv") x y
1367 MO_NatU_Rem -> idiv SLIT(".urem") x y
1369 MO_Flt_Add -> trivialFCode FloatRep FADD x y
1370 MO_Flt_Sub -> trivialFCode FloatRep FSUB x y
1371 MO_Flt_Mul -> trivialFCode FloatRep FMUL x y
1372 MO_Flt_Div -> trivialFCode FloatRep FDIV x y
1374 MO_Dbl_Add -> trivialFCode DoubleRep FADD x y
1375 MO_Dbl_Sub -> trivialFCode DoubleRep FSUB x y
1376 MO_Dbl_Mul -> trivialFCode DoubleRep FMUL x y
1377 MO_Dbl_Div -> trivialFCode DoubleRep FDIV x y
1379 MO_Nat_And -> trivialCode (AND False) x y
1380 MO_Nat_Or -> trivialCode (OR False) x y
1381 MO_Nat_Xor -> trivialCode (XOR False) x y
1383 MO_Nat_Shl -> trivialCode SLL x y
1384 MO_Nat_Shr -> trivialCode SRL x y
1385 MO_Nat_Sar -> trivialCode SRA x y
1387 MO_Flt_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1388 [promote x, promote y])
1389 where promote x = StMachOp MO_Flt_to_Dbl [x]
1390 MO_Dbl_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1393 other -> pprPanic "getRegister(sparc) - binary StMachOp (1)" (pprMachOp mop)
1395 idiv fn x y = getRegister (StCall fn CCallConv IntRep [x, y])
1397 --------------------
1398 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1400 = getNewRegNCG IntRep `thenNat` \ t1 ->
1401 getNewRegNCG IntRep `thenNat` \ t2 ->
1402 getNewRegNCG IntRep `thenNat` \ res_lo ->
1403 getNewRegNCG IntRep `thenNat` \ res_hi ->
1404 getRegister a1 `thenNat` \ reg1 ->
1405 getRegister a2 `thenNat` \ reg2 ->
1406 let code1 = registerCode reg1 t1
1407 code2 = registerCode reg2 t2
1408 src1 = registerName reg1 t1
1409 src2 = registerName reg2 t2
1410 code dst = code1 `appOL` code2 `appOL`
1412 SMUL False src1 (RIReg src2) res_lo,
1414 SRA res_lo (RIImm (ImmInt 31)) res_lo,
1415 SUB False False res_lo (RIReg res_hi) dst
1418 returnNat (Any IntRep code)
1420 getRegister (StInd pk mem)
1421 = getAmode mem `thenNat` \ amode ->
1423 code = amodeCode amode
1424 src = amodeAddr amode
1425 size = primRepToSize pk
1426 code__2 dst = code `snocOL` LD size src dst
1428 returnNat (Any pk code__2)
1430 getRegister (StInt i)
1433 src = ImmInt (fromInteger i)
1434 code dst = unitOL (OR False g0 (RIImm src) dst)
1436 returnNat (Any IntRep code)
1442 SETHI (HI imm__2) dst,
1443 OR False dst (RIImm (LO imm__2)) dst]
1445 returnNat (Any PtrRep code)
1447 = ncgPrimopMoan "getRegister(sparc)" (pprStixExpr leaf)
1450 imm__2 = case imm of Just x -> x
1452 #endif {- sparc_TARGET_ARCH -}
1454 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1458 %************************************************************************
1460 \subsection{The @Amode@ type}
1462 %************************************************************************
1464 @Amode@s: Memory addressing modes passed up the tree.
1466 data Amode = Amode MachRegsAddr InstrBlock
1468 amodeAddr (Amode addr _) = addr
1469 amodeCode (Amode _ code) = code
1472 Now, given a tree (the argument to an StInd) that references memory,
1473 produce a suitable addressing mode.
1475 A Rule of the Game (tm) for Amodes: use of the addr bit must
1476 immediately follow use of the code part, since the code part puts
1477 values in registers which the addr then refers to. So you can't put
1478 anything in between, lest it overwrite some of those registers. If
1479 you need to do some other computation between the code part and use of
1480 the addr bit, first store the effective address from the amode in a
1481 temporary, then do the other computation, and then use the temporary:
1485 ... other computation ...
1489 getAmode :: StixExpr -> NatM Amode
1491 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1493 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1495 #if alpha_TARGET_ARCH
1497 getAmode (StPrim IntSubOp [x, StInt i])
1498 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1499 getRegister x `thenNat` \ register ->
1501 code = registerCode register tmp
1502 reg = registerName register tmp
1503 off = ImmInt (-(fromInteger i))
1505 returnNat (Amode (AddrRegImm reg off) code)
1507 getAmode (StPrim IntAddOp [x, StInt i])
1508 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1509 getRegister x `thenNat` \ register ->
1511 code = registerCode register tmp
1512 reg = registerName register tmp
1513 off = ImmInt (fromInteger i)
1515 returnNat (Amode (AddrRegImm reg off) code)
1519 = returnNat (Amode (AddrImm imm__2) id)
1522 imm__2 = case imm of Just x -> x
1525 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1526 getRegister other `thenNat` \ register ->
1528 code = registerCode register tmp
1529 reg = registerName register tmp
1531 returnNat (Amode (AddrReg reg) code)
1533 #endif {- alpha_TARGET_ARCH -}
1535 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1537 #if i386_TARGET_ARCH
1539 -- This is all just ridiculous, since it carefully undoes
1540 -- what mangleIndexTree has just done.
1541 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1542 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1543 getRegister x `thenNat` \ register ->
1545 code = registerCode register tmp
1546 reg = registerName register tmp
1547 off = ImmInt (-(fromInteger i))
1549 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1551 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1553 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1556 imm__2 = case imm of Just x -> x
1558 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1559 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1560 getRegister x `thenNat` \ register ->
1562 code = registerCode register tmp
1563 reg = registerName register tmp
1564 off = ImmInt (fromInteger i)
1566 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1568 getAmode (StMachOp MO_Nat_Add [x, StMachOp MO_Nat_Shl [y, StInt shift]])
1569 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1570 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1571 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1572 getRegister x `thenNat` \ register1 ->
1573 getRegister y `thenNat` \ register2 ->
1575 code1 = registerCode register1 tmp1
1576 reg1 = registerName register1 tmp1
1577 code2 = registerCode register2 tmp2
1578 reg2 = registerName register2 tmp2
1579 code__2 = code1 `appOL` code2
1580 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1582 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1587 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1590 imm__2 = case imm of Just x -> x
1593 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1594 getRegister other `thenNat` \ register ->
1596 code = registerCode register tmp
1597 reg = registerName register tmp
1599 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1601 #endif {- i386_TARGET_ARCH -}
1603 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1605 #if sparc_TARGET_ARCH
1607 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1609 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1610 getRegister x `thenNat` \ register ->
1612 code = registerCode register tmp
1613 reg = registerName register tmp
1614 off = ImmInt (-(fromInteger i))
1616 returnNat (Amode (AddrRegImm reg off) code)
1619 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1621 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1622 getRegister x `thenNat` \ register ->
1624 code = registerCode register tmp
1625 reg = registerName register tmp
1626 off = ImmInt (fromInteger i)
1628 returnNat (Amode (AddrRegImm reg off) code)
1630 getAmode (StMachOp MO_Nat_Add [x, y])
1631 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1632 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1633 getRegister x `thenNat` \ register1 ->
1634 getRegister y `thenNat` \ register2 ->
1636 code1 = registerCode register1 tmp1
1637 reg1 = registerName register1 tmp1
1638 code2 = registerCode register2 tmp2
1639 reg2 = registerName register2 tmp2
1640 code__2 = code1 `appOL` code2
1642 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1646 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1648 code = unitOL (SETHI (HI imm__2) tmp)
1650 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1653 imm__2 = case imm of Just x -> x
1656 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1657 getRegister other `thenNat` \ register ->
1659 code = registerCode register tmp
1660 reg = registerName register tmp
1663 returnNat (Amode (AddrRegImm reg off) code)
1665 #endif {- sparc_TARGET_ARCH -}
1667 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1670 %************************************************************************
1672 \subsection{The @CondCode@ type}
1674 %************************************************************************
1676 Condition codes passed up the tree.
1678 data CondCode = CondCode Bool Cond InstrBlock
1680 condName (CondCode _ cond _) = cond
1681 condFloat (CondCode is_float _ _) = is_float
1682 condCode (CondCode _ _ code) = code
1685 Set up a condition code for a conditional branch.
1688 getCondCode :: StixExpr -> NatM CondCode
1690 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1692 #if alpha_TARGET_ARCH
1693 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1694 #endif {- alpha_TARGET_ARCH -}
1696 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1698 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1699 -- yes, they really do seem to want exactly the same!
1701 getCondCode (StMachOp mop [x, y])
1703 MO_32U_Gt -> condIntCode GTT x y
1704 MO_32U_Ge -> condIntCode GE x y
1705 MO_32U_Eq -> condIntCode EQQ x y
1706 MO_32U_Ne -> condIntCode NE x y
1707 MO_32U_Lt -> condIntCode LTT x y
1708 MO_32U_Le -> condIntCode LE x y
1710 MO_Nat_Eq -> condIntCode EQQ x y
1711 MO_Nat_Ne -> condIntCode NE x y
1713 MO_NatS_Gt -> condIntCode GTT x y
1714 MO_NatS_Ge -> condIntCode GE x y
1715 MO_NatS_Lt -> condIntCode LTT x y
1716 MO_NatS_Le -> condIntCode LE x y
1718 MO_NatU_Gt -> condIntCode GU x y
1719 MO_NatU_Ge -> condIntCode GEU x y
1720 MO_NatU_Lt -> condIntCode LU x y
1721 MO_NatU_Le -> condIntCode LEU x y
1723 MO_Flt_Gt -> condFltCode GTT x y
1724 MO_Flt_Ge -> condFltCode GE x y
1725 MO_Flt_Eq -> condFltCode EQQ x y
1726 MO_Flt_Ne -> condFltCode NE x y
1727 MO_Flt_Lt -> condFltCode LTT x y
1728 MO_Flt_Le -> condFltCode LE x y
1730 MO_Dbl_Gt -> condFltCode GTT x y
1731 MO_Dbl_Ge -> condFltCode GE x y
1732 MO_Dbl_Eq -> condFltCode EQQ x y
1733 MO_Dbl_Ne -> condFltCode NE x y
1734 MO_Dbl_Lt -> condFltCode LTT x y
1735 MO_Dbl_Le -> condFltCode LE x y
1737 other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
1739 getCondCode other = pprPanic "getCondCode(2)(x86,sparc)" (pprStixExpr other)
1741 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1743 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1748 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1749 passed back up the tree.
1752 condIntCode, condFltCode :: Cond -> StixExpr -> StixExpr -> NatM CondCode
1754 #if alpha_TARGET_ARCH
1755 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1756 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1757 #endif {- alpha_TARGET_ARCH -}
1759 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1760 #if i386_TARGET_ARCH
1762 -- memory vs immediate
1763 condIntCode cond (StInd pk x) y
1764 | Just i <- maybeImm y
1765 = getAmode x `thenNat` \ amode ->
1767 code1 = amodeCode amode
1768 x__2 = amodeAddr amode
1769 sz = primRepToSize pk
1770 code__2 = code1 `snocOL`
1771 CMP sz (OpImm i) (OpAddr x__2)
1773 returnNat (CondCode False cond code__2)
1776 condIntCode cond x (StInt 0)
1777 = getRegister x `thenNat` \ register1 ->
1778 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1780 code1 = registerCode register1 tmp1
1781 src1 = registerName register1 tmp1
1782 code__2 = code1 `snocOL`
1783 TEST L (OpReg src1) (OpReg src1)
1785 returnNat (CondCode False cond code__2)
1787 -- anything vs immediate
1788 condIntCode cond x y
1789 | Just i <- maybeImm y
1790 = getRegister x `thenNat` \ register1 ->
1791 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1793 code1 = registerCode register1 tmp1
1794 src1 = registerName register1 tmp1
1795 code__2 = code1 `snocOL`
1796 CMP L (OpImm i) (OpReg src1)
1798 returnNat (CondCode False cond code__2)
1800 -- memory vs anything
1801 condIntCode cond (StInd pk x) y
1802 = getAmode x `thenNat` \ amode_x ->
1803 getRegister y `thenNat` \ reg_y ->
1804 getNewRegNCG IntRep `thenNat` \ tmp ->
1806 c_x = amodeCode amode_x
1807 am_x = amodeAddr amode_x
1808 c_y = registerCode reg_y tmp
1809 r_y = registerName reg_y tmp
1810 sz = primRepToSize pk
1812 -- optimisation: if there's no code for x, just an amode,
1813 -- use whatever reg y winds up in. Assumes that c_y doesn't
1814 -- clobber any regs in the amode am_x, which I'm not sure is
1815 -- justified. The otherwise clause makes the same assumption.
1816 code__2 | isNilOL c_x
1818 CMP sz (OpReg r_y) (OpAddr am_x)
1822 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1824 CMP sz (OpReg tmp) (OpAddr am_x)
1826 returnNat (CondCode False cond code__2)
1828 -- anything vs memory
1830 condIntCode cond y (StInd pk x)
1831 = getAmode x `thenNat` \ amode_x ->
1832 getRegister y `thenNat` \ reg_y ->
1833 getNewRegNCG IntRep `thenNat` \ tmp ->
1835 c_x = amodeCode amode_x
1836 am_x = amodeAddr amode_x
1837 c_y = registerCode reg_y tmp
1838 r_y = registerName reg_y tmp
1839 sz = primRepToSize pk
1840 -- same optimisation and nagging doubts as previous clause
1841 code__2 | isNilOL c_x
1843 CMP sz (OpAddr am_x) (OpReg r_y)
1847 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1849 CMP sz (OpAddr am_x) (OpReg tmp)
1851 returnNat (CondCode False cond code__2)
1853 -- anything vs anything
1854 condIntCode cond x y
1855 = getRegister x `thenNat` \ register1 ->
1856 getRegister y `thenNat` \ register2 ->
1857 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1858 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1860 code1 = registerCode register1 tmp1
1861 src1 = registerName register1 tmp1
1862 code2 = registerCode register2 tmp2
1863 src2 = registerName register2 tmp2
1864 code__2 = code1 `snocOL`
1865 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1867 CMP L (OpReg src2) (OpReg tmp1)
1869 returnNat (CondCode False cond code__2)
1872 condFltCode cond x y
1873 = getRegister x `thenNat` \ register1 ->
1874 getRegister y `thenNat` \ register2 ->
1875 getNewRegNCG (registerRep register1)
1877 getNewRegNCG (registerRep register2)
1879 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1881 pk1 = registerRep register1
1882 code1 = registerCode register1 tmp1
1883 src1 = registerName register1 tmp1
1885 code2 = registerCode register2 tmp2
1886 src2 = registerName register2 tmp2
1888 code__2 | isAny register1
1889 = code1 `appOL` -- result in tmp1
1891 GCMP (primRepToSize pk1) tmp1 src2
1895 GMOV src1 tmp1 `appOL`
1897 GCMP (primRepToSize pk1) tmp1 src2
1899 {- On the 486, the flags set by FP compare are the unsigned ones!
1900 (This looks like a HACK to me. WDP 96/03)
1902 fix_FP_cond :: Cond -> Cond
1904 fix_FP_cond GE = GEU
1905 fix_FP_cond GTT = GU
1906 fix_FP_cond LTT = LU
1907 fix_FP_cond LE = LEU
1908 fix_FP_cond any = any
1910 returnNat (CondCode True (fix_FP_cond cond) code__2)
1912 #endif {- i386_TARGET_ARCH -}
1914 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1916 #if sparc_TARGET_ARCH
1918 condIntCode cond x (StInt y)
1920 = getRegister x `thenNat` \ register ->
1921 getNewRegNCG IntRep `thenNat` \ tmp ->
1923 code = registerCode register tmp
1924 src1 = registerName register tmp
1925 src2 = ImmInt (fromInteger y)
1926 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1928 returnNat (CondCode False cond code__2)
1930 condIntCode cond x y
1931 = getRegister x `thenNat` \ register1 ->
1932 getRegister y `thenNat` \ register2 ->
1933 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1934 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1936 code1 = registerCode register1 tmp1
1937 src1 = registerName register1 tmp1
1938 code2 = registerCode register2 tmp2
1939 src2 = registerName register2 tmp2
1940 code__2 = code1 `appOL` code2 `snocOL`
1941 SUB False True src1 (RIReg src2) g0
1943 returnNat (CondCode False cond code__2)
1946 condFltCode cond x y
1947 = getRegister x `thenNat` \ register1 ->
1948 getRegister y `thenNat` \ register2 ->
1949 getNewRegNCG (registerRep register1)
1951 getNewRegNCG (registerRep register2)
1953 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1955 promote x = FxTOy F DF x tmp
1957 pk1 = registerRep register1
1958 code1 = registerCode register1 tmp1
1959 src1 = registerName register1 tmp1
1961 pk2 = registerRep register2
1962 code2 = registerCode register2 tmp2
1963 src2 = registerName register2 tmp2
1967 code1 `appOL` code2 `snocOL`
1968 FCMP True (primRepToSize pk1) src1 src2
1969 else if pk1 == FloatRep then
1970 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1971 FCMP True DF tmp src2
1973 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1974 FCMP True DF src1 tmp
1976 returnNat (CondCode True cond code__2)
1978 #endif {- sparc_TARGET_ARCH -}
1980 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1983 %************************************************************************
1985 \subsection{Generating assignments}
1987 %************************************************************************
1989 Assignments are really at the heart of the whole code generation
1990 business. Almost all top-level nodes of any real importance are
1991 assignments, which correspond to loads, stores, or register transfers.
1992 If we're really lucky, some of the register transfers will go away,
1993 because we can use the destination register to complete the code
1994 generation for the right hand side. This only fails when the right
1995 hand side is forced into a fixed register (e.g. the result of a call).
1998 assignMem_IntCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
1999 assignReg_IntCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
2001 assignMem_FltCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
2002 assignReg_FltCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
2004 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2006 #if alpha_TARGET_ARCH
2008 assignIntCode pk (StInd _ dst) src
2009 = getNewRegNCG IntRep `thenNat` \ tmp ->
2010 getAmode dst `thenNat` \ amode ->
2011 getRegister src `thenNat` \ register ->
2013 code1 = amodeCode amode []
2014 dst__2 = amodeAddr amode
2015 code2 = registerCode register tmp []
2016 src__2 = registerName register tmp
2017 sz = primRepToSize pk
2018 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2022 assignIntCode pk dst src
2023 = getRegister dst `thenNat` \ register1 ->
2024 getRegister src `thenNat` \ register2 ->
2026 dst__2 = registerName register1 zeroh
2027 code = registerCode register2 dst__2
2028 src__2 = registerName register2 dst__2
2029 code__2 = if isFixed register2
2030 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
2035 #endif {- alpha_TARGET_ARCH -}
2037 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2039 #if i386_TARGET_ARCH
2041 -- non-FP assignment to memory
2042 assignMem_IntCode pk addr src
2043 = getAmode addr `thenNat` \ amode ->
2044 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
2045 getNewRegNCG PtrRep `thenNat` \ tmp ->
2047 -- In general, if the address computation for dst may require
2048 -- some insns preceding the addressing mode itself. So there's
2049 -- no guarantee that the code for dst and the code for src won't
2050 -- write the same register. This means either the address or
2051 -- the value needs to be copied into a temporary. We detect the
2052 -- common case where the amode has no code, and elide the copy.
2053 codea = amodeCode amode
2054 dst__a = amodeAddr amode
2056 code | isNilOL codea
2058 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
2061 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
2063 MOV (primRepToSize pk) opsrc
2064 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
2070 -> NatM (InstrBlock,Operand) -- code, operator
2073 | Just x <- maybeImm op
2074 = returnNat (nilOL, OpImm x)
2077 = getRegister op `thenNat` \ register ->
2078 getNewRegNCG (registerRep register)
2080 let code = registerCode register tmp
2081 reg = registerName register tmp
2083 returnNat (code, OpReg reg)
2085 -- Assign; dst is a reg, rhs is mem
2086 assignReg_IntCode pk reg (StInd pks src)
2087 = getNewRegNCG PtrRep `thenNat` \ tmp ->
2088 getAmode src `thenNat` \ amode ->
2089 getRegisterReg reg `thenNat` \ reg_dst ->
2091 c_addr = amodeCode amode
2092 am_addr = amodeAddr amode
2093 r_dst = registerName reg_dst tmp
2094 szs = primRepToSize pks
2103 code = c_addr `snocOL`
2104 opc (OpAddr am_addr) (OpReg r_dst)
2108 -- dst is a reg, but src could be anything
2109 assignReg_IntCode pk reg src
2110 = getRegisterReg reg `thenNat` \ registerd ->
2111 getRegister src `thenNat` \ registers ->
2112 getNewRegNCG IntRep `thenNat` \ tmp ->
2114 r_dst = registerName registerd tmp
2115 r_src = registerName registers r_dst
2116 c_src = registerCode registers r_dst
2118 code = c_src `snocOL`
2119 MOV L (OpReg r_src) (OpReg r_dst)
2123 #endif {- i386_TARGET_ARCH -}
2125 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2127 #if sparc_TARGET_ARCH
2129 assignMem_IntCode pk addr src
2130 = getNewRegNCG IntRep `thenNat` \ tmp ->
2131 getAmode addr `thenNat` \ amode ->
2132 getRegister src `thenNat` \ register ->
2134 code1 = amodeCode amode
2135 dst__2 = amodeAddr amode
2136 code2 = registerCode register tmp
2137 src__2 = registerName register tmp
2138 sz = primRepToSize pk
2139 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
2143 assignReg_IntCode pk reg src
2144 = getRegister src `thenNat` \ register2 ->
2145 getRegisterReg reg `thenNat` \ register1 ->
2147 dst__2 = registerName register1 g0
2148 code = registerCode register2 dst__2
2149 src__2 = registerName register2 dst__2
2150 code__2 = if isFixed register2
2151 then code `snocOL` OR False g0 (RIReg src__2) dst__2
2156 #endif {- sparc_TARGET_ARCH -}
2158 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2161 % --------------------------------
2162 Floating-point assignments:
2163 % --------------------------------
2166 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2167 #if alpha_TARGET_ARCH
2169 assignFltCode pk (StInd _ dst) src
2170 = getNewRegNCG pk `thenNat` \ tmp ->
2171 getAmode dst `thenNat` \ amode ->
2172 getRegister src `thenNat` \ register ->
2174 code1 = amodeCode amode []
2175 dst__2 = amodeAddr amode
2176 code2 = registerCode register tmp []
2177 src__2 = registerName register tmp
2178 sz = primRepToSize pk
2179 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2183 assignFltCode pk dst src
2184 = getRegister dst `thenNat` \ register1 ->
2185 getRegister src `thenNat` \ register2 ->
2187 dst__2 = registerName register1 zeroh
2188 code = registerCode register2 dst__2
2189 src__2 = registerName register2 dst__2
2190 code__2 = if isFixed register2
2191 then code . mkSeqInstr (FMOV src__2 dst__2)
2196 #endif {- alpha_TARGET_ARCH -}
2198 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2200 #if i386_TARGET_ARCH
2202 -- Floating point assignment to memory
2203 assignMem_FltCode pk addr src
2204 = getRegister src `thenNat` \ reg_src ->
2205 getRegister addr `thenNat` \ reg_addr ->
2206 getNewRegNCG pk `thenNat` \ tmp_src ->
2207 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
2208 let r_src = registerName reg_src tmp_src
2209 c_src = registerCode reg_src tmp_src
2210 r_addr = registerName reg_addr tmp_addr
2211 c_addr = registerCode reg_addr tmp_addr
2212 sz = primRepToSize pk
2214 code = c_src `appOL`
2215 -- no need to preserve r_src across the addr computation,
2216 -- since r_src must be a float reg
2217 -- whilst r_addr is an int reg
2220 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
2224 -- Floating point assignment to a register/temporary
2225 assignReg_FltCode pk reg src
2226 = getRegisterReg reg `thenNat` \ reg_dst ->
2227 getRegister src `thenNat` \ reg_src ->
2228 getNewRegNCG pk `thenNat` \ tmp ->
2230 r_dst = registerName reg_dst tmp
2231 r_src = registerName reg_src r_dst
2232 c_src = registerCode reg_src r_dst
2234 code = if isFixed reg_src
2235 then c_src `snocOL` GMOV r_src r_dst
2241 #endif {- i386_TARGET_ARCH -}
2243 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2245 #if sparc_TARGET_ARCH
2247 -- Floating point assignment to memory
2248 assignMem_FltCode pk addr src
2249 = getNewRegNCG pk `thenNat` \ tmp1 ->
2250 getAmode addr `thenNat` \ amode ->
2251 getRegister src `thenNat` \ register ->
2253 sz = primRepToSize pk
2254 dst__2 = amodeAddr amode
2256 code1 = amodeCode amode
2257 code2 = registerCode register tmp1
2259 src__2 = registerName register tmp1
2260 pk__2 = registerRep register
2261 sz__2 = primRepToSize pk__2
2263 code__2 = code1 `appOL` code2 `appOL`
2265 then unitOL (ST sz src__2 dst__2)
2266 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
2270 -- Floating point assignment to a register/temporary
2271 -- Why is this so bizarrely ugly?
2272 assignReg_FltCode pk reg src
2273 = getRegisterReg reg `thenNat` \ register1 ->
2274 getRegister src `thenNat` \ register2 ->
2276 pk__2 = registerRep register2
2277 sz__2 = primRepToSize pk__2
2279 getNewRegNCG pk__2 `thenNat` \ tmp ->
2281 sz = primRepToSize pk
2282 dst__2 = registerName register1 g0 -- must be Fixed
2283 reg__2 = if pk /= pk__2 then tmp else dst__2
2284 code = registerCode register2 reg__2
2285 src__2 = registerName register2 reg__2
2288 code `snocOL` FxTOy sz__2 sz src__2 dst__2
2289 else if isFixed register2 then
2290 code `snocOL` FMOV sz src__2 dst__2
2296 #endif {- sparc_TARGET_ARCH -}
2298 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2301 %************************************************************************
2303 \subsection{Generating an unconditional branch}
2305 %************************************************************************
2307 We accept two types of targets: an immediate CLabel or a tree that
2308 gets evaluated into a register. Any CLabels which are AsmTemporaries
2309 are assumed to be in the local block of code, close enough for a
2310 branch instruction. Other CLabels are assumed to be far away.
2312 (If applicable) Do not fill the delay slots here; you will confuse the
2316 genJump :: DestInfo -> StixExpr{-the branch target-} -> NatM InstrBlock
2318 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2320 #if alpha_TARGET_ARCH
2322 genJump (StCLbl lbl)
2323 | isAsmTemp lbl = returnInstr (BR target)
2324 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2326 target = ImmCLbl lbl
2329 = getRegister tree `thenNat` \ register ->
2330 getNewRegNCG PtrRep `thenNat` \ tmp ->
2332 dst = registerName register pv
2333 code = registerCode register pv
2334 target = registerName register pv
2336 if isFixed register then
2337 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2339 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2341 #endif {- alpha_TARGET_ARCH -}
2343 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2345 #if i386_TARGET_ARCH
2347 genJump dsts (StInd pk mem)
2348 = getAmode mem `thenNat` \ amode ->
2350 code = amodeCode amode
2351 target = amodeAddr amode
2353 returnNat (code `snocOL` JMP dsts (OpAddr target))
2357 = returnNat (unitOL (JMP dsts (OpImm target)))
2360 = getRegister tree `thenNat` \ register ->
2361 getNewRegNCG PtrRep `thenNat` \ tmp ->
2363 code = registerCode register tmp
2364 target = registerName register tmp
2366 returnNat (code `snocOL` JMP dsts (OpReg target))
2369 target = case imm of Just x -> x
2371 #endif {- i386_TARGET_ARCH -}
2373 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2375 #if sparc_TARGET_ARCH
2377 genJump dsts (StCLbl lbl)
2378 | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
2379 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2380 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
2382 target = ImmCLbl lbl
2385 = getRegister tree `thenNat` \ register ->
2386 getNewRegNCG PtrRep `thenNat` \ tmp ->
2388 code = registerCode register tmp
2389 target = registerName register tmp
2391 returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
2393 #endif {- sparc_TARGET_ARCH -}
2395 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2398 %************************************************************************
2400 \subsection{Conditional jumps}
2402 %************************************************************************
2404 Conditional jumps are always to local labels, so we can use branch
2405 instructions. We peek at the arguments to decide what kind of
2408 ALPHA: For comparisons with 0, we're laughing, because we can just do
2409 the desired conditional branch.
2411 I386: First, we have to ensure that the condition
2412 codes are set according to the supplied comparison operation.
2414 SPARC: First, we have to ensure that the condition codes are set
2415 according to the supplied comparison operation. We generate slightly
2416 different code for floating point comparisons, because a floating
2417 point operation cannot directly precede a @BF@. We assume the worst
2418 and fill that slot with a @NOP@.
2420 SPARC: Do not fill the delay slots here; you will confuse the register
2425 :: CLabel -- the branch target
2426 -> StixExpr -- the condition on which to branch
2429 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2431 #if alpha_TARGET_ARCH
2433 genCondJump lbl (StPrim op [x, StInt 0])
2434 = getRegister x `thenNat` \ register ->
2435 getNewRegNCG (registerRep register)
2438 code = registerCode register tmp
2439 value = registerName register tmp
2440 pk = registerRep register
2441 target = ImmCLbl lbl
2443 returnSeq code [BI (cmpOp op) value target]
2445 cmpOp CharGtOp = GTT
2447 cmpOp CharEqOp = EQQ
2449 cmpOp CharLtOp = LTT
2458 cmpOp WordGeOp = ALWAYS
2459 cmpOp WordEqOp = EQQ
2461 cmpOp WordLtOp = NEVER
2462 cmpOp WordLeOp = EQQ
2464 cmpOp AddrGeOp = ALWAYS
2465 cmpOp AddrEqOp = EQQ
2467 cmpOp AddrLtOp = NEVER
2468 cmpOp AddrLeOp = EQQ
2470 genCondJump lbl (StPrim op [x, StDouble 0.0])
2471 = getRegister x `thenNat` \ register ->
2472 getNewRegNCG (registerRep register)
2475 code = registerCode register tmp
2476 value = registerName register tmp
2477 pk = registerRep register
2478 target = ImmCLbl lbl
2480 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2482 cmpOp FloatGtOp = GTT
2483 cmpOp FloatGeOp = GE
2484 cmpOp FloatEqOp = EQQ
2485 cmpOp FloatNeOp = NE
2486 cmpOp FloatLtOp = LTT
2487 cmpOp FloatLeOp = LE
2488 cmpOp DoubleGtOp = GTT
2489 cmpOp DoubleGeOp = GE
2490 cmpOp DoubleEqOp = EQQ
2491 cmpOp DoubleNeOp = NE
2492 cmpOp DoubleLtOp = LTT
2493 cmpOp DoubleLeOp = LE
2495 genCondJump lbl (StPrim op [x, y])
2497 = trivialFCode pr instr x y `thenNat` \ register ->
2498 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2500 code = registerCode register tmp
2501 result = registerName register tmp
2502 target = ImmCLbl lbl
2504 returnNat (code . mkSeqInstr (BF cond result target))
2506 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2508 fltCmpOp op = case op of
2522 (instr, cond) = case op of
2523 FloatGtOp -> (FCMP TF LE, EQQ)
2524 FloatGeOp -> (FCMP TF LTT, EQQ)
2525 FloatEqOp -> (FCMP TF EQQ, NE)
2526 FloatNeOp -> (FCMP TF EQQ, EQQ)
2527 FloatLtOp -> (FCMP TF LTT, NE)
2528 FloatLeOp -> (FCMP TF LE, NE)
2529 DoubleGtOp -> (FCMP TF LE, EQQ)
2530 DoubleGeOp -> (FCMP TF LTT, EQQ)
2531 DoubleEqOp -> (FCMP TF EQQ, NE)
2532 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2533 DoubleLtOp -> (FCMP TF LTT, NE)
2534 DoubleLeOp -> (FCMP TF LE, NE)
2536 genCondJump lbl (StPrim op [x, y])
2537 = trivialCode instr x y `thenNat` \ register ->
2538 getNewRegNCG IntRep `thenNat` \ tmp ->
2540 code = registerCode register tmp
2541 result = registerName register tmp
2542 target = ImmCLbl lbl
2544 returnNat (code . mkSeqInstr (BI cond result target))
2546 (instr, cond) = case op of
2547 CharGtOp -> (CMP LE, EQQ)
2548 CharGeOp -> (CMP LTT, EQQ)
2549 CharEqOp -> (CMP EQQ, NE)
2550 CharNeOp -> (CMP EQQ, EQQ)
2551 CharLtOp -> (CMP LTT, NE)
2552 CharLeOp -> (CMP LE, NE)
2553 IntGtOp -> (CMP LE, EQQ)
2554 IntGeOp -> (CMP LTT, EQQ)
2555 IntEqOp -> (CMP EQQ, NE)
2556 IntNeOp -> (CMP EQQ, EQQ)
2557 IntLtOp -> (CMP LTT, NE)
2558 IntLeOp -> (CMP LE, NE)
2559 WordGtOp -> (CMP ULE, EQQ)
2560 WordGeOp -> (CMP ULT, EQQ)
2561 WordEqOp -> (CMP EQQ, NE)
2562 WordNeOp -> (CMP EQQ, EQQ)
2563 WordLtOp -> (CMP ULT, NE)
2564 WordLeOp -> (CMP ULE, NE)
2565 AddrGtOp -> (CMP ULE, EQQ)
2566 AddrGeOp -> (CMP ULT, EQQ)
2567 AddrEqOp -> (CMP EQQ, NE)
2568 AddrNeOp -> (CMP EQQ, EQQ)
2569 AddrLtOp -> (CMP ULT, NE)
2570 AddrLeOp -> (CMP ULE, NE)
2572 #endif {- alpha_TARGET_ARCH -}
2574 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2576 #if i386_TARGET_ARCH
2578 genCondJump lbl bool
2579 = getCondCode bool `thenNat` \ condition ->
2581 code = condCode condition
2582 cond = condName condition
2584 returnNat (code `snocOL` JXX cond lbl)
2586 #endif {- i386_TARGET_ARCH -}
2588 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2590 #if sparc_TARGET_ARCH
2592 genCondJump lbl bool
2593 = getCondCode bool `thenNat` \ condition ->
2595 code = condCode condition
2596 cond = condName condition
2597 target = ImmCLbl lbl
2602 if condFloat condition
2603 then [NOP, BF cond False target, NOP]
2604 else [BI cond False target, NOP]
2608 #endif {- sparc_TARGET_ARCH -}
2610 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2613 %************************************************************************
2615 \subsection{Generating C calls}
2617 %************************************************************************
2619 Now the biggest nightmare---calls. Most of the nastiness is buried in
2620 @get_arg@, which moves the arguments to the correct registers/stack
2621 locations. Apart from that, the code is easy.
2623 (If applicable) Do not fill the delay slots here; you will confuse the
2628 :: FAST_STRING -- function to call
2630 -> PrimRep -- type of the result
2631 -> [StixExpr] -- arguments (of mixed type)
2634 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2636 #if alpha_TARGET_ARCH
2638 genCCall fn cconv kind args
2639 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2640 `thenNat` \ ((unused,_), argCode) ->
2642 nRegs = length allArgRegs - length unused
2643 code = asmSeqThen (map ($ []) argCode)
2646 LDA pv (AddrImm (ImmLab (ptext fn))),
2647 JSR ra (AddrReg pv) nRegs,
2648 LDGP gp (AddrReg ra)]
2650 ------------------------
2651 {- Try to get a value into a specific register (or registers) for
2652 a call. The first 6 arguments go into the appropriate
2653 argument register (separate registers for integer and floating
2654 point arguments, but used in lock-step), and the remaining
2655 arguments are dumped to the stack, beginning at 0(sp). Our
2656 first argument is a pair of the list of remaining argument
2657 registers to be assigned for this call and the next stack
2658 offset to use for overflowing arguments. This way,
2659 @get_Arg@ can be applied to all of a call's arguments using
2663 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2664 -> StixTree -- Current argument
2665 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2667 -- We have to use up all of our argument registers first...
2669 get_arg ((iDst,fDst):dsts, offset) arg
2670 = getRegister arg `thenNat` \ register ->
2672 reg = if isFloatingRep pk then fDst else iDst
2673 code = registerCode register reg
2674 src = registerName register reg
2675 pk = registerRep register
2678 if isFloatingRep pk then
2679 ((dsts, offset), if isFixed register then
2680 code . mkSeqInstr (FMOV src fDst)
2683 ((dsts, offset), if isFixed register then
2684 code . mkSeqInstr (OR src (RIReg src) iDst)
2687 -- Once we have run out of argument registers, we move to the
2690 get_arg ([], offset) arg
2691 = getRegister arg `thenNat` \ register ->
2692 getNewRegNCG (registerRep register)
2695 code = registerCode register tmp
2696 src = registerName register tmp
2697 pk = registerRep register
2698 sz = primRepToSize pk
2700 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2702 #endif {- alpha_TARGET_ARCH -}
2704 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2706 #if i386_TARGET_ARCH
2708 genCCall fn cconv ret_rep [StInt i]
2709 | fn == SLIT ("PerformGC_wrapper")
2711 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2712 CALL (ImmLit (ptext (if underscorePrefix
2713 then (SLIT ("_PerformGC_wrapper"))
2714 else (SLIT ("PerformGC_wrapper")))))
2720 genCCall fn cconv ret_rep args
2722 (reverse args) `thenNat` \ sizes_n_codes ->
2723 getDeltaNat `thenNat` \ delta ->
2724 let (sizes, codes) = unzip sizes_n_codes
2725 tot_arg_size = sum sizes
2726 code2 = concatOL codes
2728 [CALL (fn__2 tot_arg_size)]
2730 -- Deallocate parameters after call for ccall;
2731 -- but not for stdcall (callee does it)
2732 (if cconv == StdCallConv then [] else
2733 [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2736 [DELTA (delta + tot_arg_size)]
2739 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2740 returnNat (code2 `appOL` call)
2743 -- function names that begin with '.' are assumed to be special
2744 -- internally generated names like '.mul,' which don't get an
2745 -- underscore prefix
2746 -- ToDo:needed (WDP 96/03) ???
2750 = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
2751 | otherwise -- General case
2752 = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
2754 stdcallsize tot_arg_size
2755 | cconv == StdCallConv = '@':show tot_arg_size
2763 push_arg :: StixExpr{-current argument-}
2764 -> NatM (Int, InstrBlock) -- argsz, code
2767 | is64BitRep arg_rep
2768 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2769 getDeltaNat `thenNat` \ delta ->
2770 setDeltaNat (delta - 8) `thenNat` \ _ ->
2771 let r_lo = VirtualRegI vr_lo
2772 r_hi = getHiVRegFromLo r_lo
2775 toOL [PUSH L (OpReg r_hi), DELTA (delta - 4),
2776 PUSH L (OpReg r_lo), DELTA (delta - 8)]
2779 = get_op arg `thenNat` \ (code, reg, sz) ->
2780 getDeltaNat `thenNat` \ delta ->
2781 arg_size sz `bind` \ size ->
2782 setDeltaNat (delta-size) `thenNat` \ _ ->
2783 if (case sz of DF -> True; F -> True; _ -> False)
2784 then returnNat (size,
2786 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2788 GST sz reg (AddrBaseIndex (Just esp)
2792 else returnNat (size,
2794 PUSH L (OpReg reg) `snocOL`
2798 arg_rep = repOfStixExpr arg
2803 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2806 = getRegister op `thenNat` \ register ->
2807 getNewRegNCG (registerRep register)
2810 code = registerCode register tmp
2811 reg = registerName register tmp
2812 pk = registerRep register
2813 sz = primRepToSize pk
2815 returnNat (code, reg, sz)
2817 #endif {- i386_TARGET_ARCH -}
2819 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2821 #if sparc_TARGET_ARCH
2823 The SPARC calling convention is an absolute
2824 nightmare. The first 6x32 bits of arguments are mapped into
2825 %o0 through %o5, and the remaining arguments are dumped to the
2826 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
2828 If we have to put args on the stack, move %o6==%sp down by
2829 the number of words to go on the stack, to ensure there's enough space.
2831 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
2832 16 words above the stack pointer is a word for the address of
2833 a structure return value. I use this as a temporary location
2834 for moving values from float to int regs. Certainly it isn't
2835 safe to put anything in the 16 words starting at %sp, since
2836 this area can get trashed at any time due to window overflows
2837 caused by signal handlers.
2839 A final complication (if the above isn't enough) is that
2840 we can't blithely calculate the arguments one by one into
2841 %o0 .. %o5. Consider the following nested calls:
2845 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
2846 the inner call will itself use %o0, which trashes the value put there
2847 in preparation for the outer call. Upshot: we need to calculate the
2848 args into temporary regs, and move those to arg regs or onto the
2849 stack only immediately prior to the call proper. Sigh.
2852 genCCall fn cconv kind args
2853 = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
2854 let (argcodes, vregss) = unzip argcode_and_vregs
2855 argcode = concatOL argcodes
2856 vregs = concat vregss
2857 n_argRegs = length allArgRegs
2858 n_argRegs_used = min (length vregs) n_argRegs
2859 (move_sp_down, move_sp_up)
2860 = let nn = length vregs - n_argRegs
2861 + 1 -- (for the road)
2864 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
2866 = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
2868 = unitOL (CALL fn__2 n_argRegs_used False)
2870 returnNat (argcode `appOL`
2871 move_sp_down `appOL`
2872 transfer_code `appOL`
2877 -- function names that begin with '.' are assumed to be special
2878 -- internally generated names like '.mul,' which don't get an
2879 -- underscore prefix
2880 -- ToDo:needed (WDP 96/03) ???
2881 fn__2 = case (_HEAD_ fn) of
2882 '.' -> ImmLit (ptext fn)
2883 _ -> ImmLab False (ptext fn)
2885 -- move args from the integer vregs into which they have been
2886 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
2887 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
2889 move_final [] _ offset -- all args done
2892 move_final (v:vs) [] offset -- out of aregs; move to stack
2893 = ST W v (spRel offset)
2894 : move_final vs [] (offset+1)
2896 move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
2897 = OR False g0 (RIReg v) a
2898 : move_final vs az offset
2900 -- generate code to calculate an argument, and move it into one
2901 -- or two integer vregs.
2902 arg_to_int_vregs :: StixExpr -> NatM (OrdList Instr, [Reg])
2903 arg_to_int_vregs arg
2904 | is64BitRep (repOfStixExpr arg)
2905 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2906 let r_lo = VirtualRegI vr_lo
2907 r_hi = getHiVRegFromLo r_lo
2908 in returnNat (code, [r_hi, r_lo])
2910 = getRegister arg `thenNat` \ register ->
2911 getNewRegNCG (registerRep register) `thenNat` \ tmp ->
2912 let code = registerCode register tmp
2913 src = registerName register tmp
2914 pk = registerRep register
2916 -- the value is in src. Get it into 1 or 2 int vregs.
2919 getNewRegNCG WordRep `thenNat` \ v1 ->
2920 getNewRegNCG WordRep `thenNat` \ v2 ->
2923 FMOV DF src f0 `snocOL`
2924 ST F f0 (spRel 16) `snocOL`
2925 LD W (spRel 16) v1 `snocOL`
2926 ST F (fPair f0) (spRel 16) `snocOL`
2932 getNewRegNCG WordRep `thenNat` \ v1 ->
2935 ST F src (spRel 16) `snocOL`
2941 getNewRegNCG WordRep `thenNat` \ v1 ->
2943 code `snocOL` OR False g0 (RIReg src) v1
2947 #endif {- sparc_TARGET_ARCH -}
2949 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2952 %************************************************************************
2954 \subsection{Support bits}
2956 %************************************************************************
2958 %************************************************************************
2960 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2962 %************************************************************************
2964 Turn those condition codes into integers now (when they appear on
2965 the right hand side of an assignment).
2967 (If applicable) Do not fill the delay slots here; you will confuse the
2971 condIntReg, condFltReg :: Cond -> StixExpr -> StixExpr -> NatM Register
2973 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2975 #if alpha_TARGET_ARCH
2976 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2977 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2978 #endif {- alpha_TARGET_ARCH -}
2980 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2982 #if i386_TARGET_ARCH
2985 = condIntCode cond x y `thenNat` \ condition ->
2986 getNewRegNCG IntRep `thenNat` \ tmp ->
2988 code = condCode condition
2989 cond = condName condition
2990 code__2 dst = code `appOL` toOL [
2991 SETCC cond (OpReg tmp),
2992 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2993 MOV L (OpReg tmp) (OpReg dst)]
2995 returnNat (Any IntRep code__2)
2998 = getNatLabelNCG `thenNat` \ lbl1 ->
2999 getNatLabelNCG `thenNat` \ lbl2 ->
3000 condFltCode cond x y `thenNat` \ condition ->
3002 code = condCode condition
3003 cond = condName condition
3004 code__2 dst = code `appOL` toOL [
3006 MOV L (OpImm (ImmInt 0)) (OpReg dst),
3009 MOV L (OpImm (ImmInt 1)) (OpReg dst),
3012 returnNat (Any IntRep code__2)
3014 #endif {- i386_TARGET_ARCH -}
3016 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3018 #if sparc_TARGET_ARCH
3020 condIntReg EQQ x (StInt 0)
3021 = getRegister x `thenNat` \ register ->
3022 getNewRegNCG IntRep `thenNat` \ tmp ->
3024 code = registerCode register tmp
3025 src = registerName register tmp
3026 code__2 dst = code `appOL` toOL [
3027 SUB False True g0 (RIReg src) g0,
3028 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3030 returnNat (Any IntRep code__2)
3033 = getRegister x `thenNat` \ register1 ->
3034 getRegister y `thenNat` \ register2 ->
3035 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3036 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3038 code1 = registerCode register1 tmp1
3039 src1 = registerName register1 tmp1
3040 code2 = registerCode register2 tmp2
3041 src2 = registerName register2 tmp2
3042 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3043 XOR False src1 (RIReg src2) dst,
3044 SUB False True g0 (RIReg dst) g0,
3045 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3047 returnNat (Any IntRep code__2)
3049 condIntReg NE x (StInt 0)
3050 = getRegister x `thenNat` \ register ->
3051 getNewRegNCG IntRep `thenNat` \ tmp ->
3053 code = registerCode register tmp
3054 src = registerName register tmp
3055 code__2 dst = code `appOL` toOL [
3056 SUB False True g0 (RIReg src) g0,
3057 ADD True False g0 (RIImm (ImmInt 0)) dst]
3059 returnNat (Any IntRep code__2)
3062 = getRegister x `thenNat` \ register1 ->
3063 getRegister y `thenNat` \ register2 ->
3064 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3065 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3067 code1 = registerCode register1 tmp1
3068 src1 = registerName register1 tmp1
3069 code2 = registerCode register2 tmp2
3070 src2 = registerName register2 tmp2
3071 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3072 XOR False src1 (RIReg src2) dst,
3073 SUB False True g0 (RIReg dst) g0,
3074 ADD True False g0 (RIImm (ImmInt 0)) dst]
3076 returnNat (Any IntRep code__2)
3079 = getNatLabelNCG `thenNat` \ lbl1 ->
3080 getNatLabelNCG `thenNat` \ lbl2 ->
3081 condIntCode cond x y `thenNat` \ condition ->
3083 code = condCode condition
3084 cond = condName condition
3085 code__2 dst = code `appOL` toOL [
3086 BI cond False (ImmCLbl lbl1), NOP,
3087 OR False g0 (RIImm (ImmInt 0)) dst,
3088 BI ALWAYS False (ImmCLbl lbl2), NOP,
3090 OR False g0 (RIImm (ImmInt 1)) dst,
3093 returnNat (Any IntRep code__2)
3096 = getNatLabelNCG `thenNat` \ lbl1 ->
3097 getNatLabelNCG `thenNat` \ lbl2 ->
3098 condFltCode cond x y `thenNat` \ condition ->
3100 code = condCode condition
3101 cond = condName condition
3102 code__2 dst = code `appOL` toOL [
3104 BF cond False (ImmCLbl lbl1), NOP,
3105 OR False g0 (RIImm (ImmInt 0)) dst,
3106 BI ALWAYS False (ImmCLbl lbl2), NOP,
3108 OR False g0 (RIImm (ImmInt 1)) dst,
3111 returnNat (Any IntRep code__2)
3113 #endif {- sparc_TARGET_ARCH -}
3115 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3118 %************************************************************************
3120 \subsubsection{@trivial*Code@: deal with trivial instructions}
3122 %************************************************************************
3124 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
3125 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
3126 for constants on the right hand side, because that's where the generic
3127 optimizer will have put them.
3129 Similarly, for unary instructions, we don't have to worry about
3130 matching an StInt as the argument, because genericOpt will already
3131 have handled the constant-folding.
3135 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
3136 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
3137 -> Maybe (Operand -> Operand -> Instr)
3138 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
3140 -> StixExpr -> StixExpr -- the two arguments
3145 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
3146 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
3147 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
3149 -> StixExpr -> StixExpr -- the two arguments
3153 :: IF_ARCH_alpha((RI -> Reg -> Instr)
3154 ,IF_ARCH_i386 ((Operand -> Instr)
3155 ,IF_ARCH_sparc((RI -> Reg -> Instr)
3157 -> StixExpr -- the one argument
3162 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
3163 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
3164 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
3166 -> StixExpr -- the one argument
3169 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3171 #if alpha_TARGET_ARCH
3173 trivialCode instr x (StInt y)
3175 = getRegister x `thenNat` \ register ->
3176 getNewRegNCG IntRep `thenNat` \ tmp ->
3178 code = registerCode register tmp
3179 src1 = registerName register tmp
3180 src2 = ImmInt (fromInteger y)
3181 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
3183 returnNat (Any IntRep code__2)
3185 trivialCode instr x y
3186 = getRegister x `thenNat` \ register1 ->
3187 getRegister y `thenNat` \ register2 ->
3188 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3189 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3191 code1 = registerCode register1 tmp1 []
3192 src1 = registerName register1 tmp1
3193 code2 = registerCode register2 tmp2 []
3194 src2 = registerName register2 tmp2
3195 code__2 dst = asmSeqThen [code1, code2] .
3196 mkSeqInstr (instr src1 (RIReg src2) dst)
3198 returnNat (Any IntRep code__2)
3201 trivialUCode instr x
3202 = getRegister x `thenNat` \ register ->
3203 getNewRegNCG IntRep `thenNat` \ tmp ->
3205 code = registerCode register tmp
3206 src = registerName register tmp
3207 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3209 returnNat (Any IntRep code__2)
3212 trivialFCode _ instr x y
3213 = getRegister x `thenNat` \ register1 ->
3214 getRegister y `thenNat` \ register2 ->
3215 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3216 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3218 code1 = registerCode register1 tmp1
3219 src1 = registerName register1 tmp1
3221 code2 = registerCode register2 tmp2
3222 src2 = registerName register2 tmp2
3224 code__2 dst = asmSeqThen [code1 [], code2 []] .
3225 mkSeqInstr (instr src1 src2 dst)
3227 returnNat (Any DoubleRep code__2)
3229 trivialUFCode _ instr x
3230 = getRegister x `thenNat` \ register ->
3231 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3233 code = registerCode register tmp
3234 src = registerName register tmp
3235 code__2 dst = code . mkSeqInstr (instr src dst)
3237 returnNat (Any DoubleRep code__2)
3239 #endif {- alpha_TARGET_ARCH -}
3241 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3243 #if i386_TARGET_ARCH
3245 The Rules of the Game are:
3247 * You cannot assume anything about the destination register dst;
3248 it may be anything, including a fixed reg.
3250 * You may compute an operand into a fixed reg, but you may not
3251 subsequently change the contents of that fixed reg. If you
3252 want to do so, first copy the value either to a temporary
3253 or into dst. You are free to modify dst even if it happens
3254 to be a fixed reg -- that's not your problem.
3256 * You cannot assume that a fixed reg will stay live over an
3257 arbitrary computation. The same applies to the dst reg.
3259 * Temporary regs obtained from getNewRegNCG are distinct from
3260 each other and from all other regs, and stay live over
3261 arbitrary computations.
3265 trivialCode instr maybe_revinstr a b
3268 = getRegister a `thenNat` \ rega ->
3271 then registerCode rega dst `bind` \ code_a ->
3273 instr (OpImm imm_b) (OpReg dst)
3274 else registerCodeF rega `bind` \ code_a ->
3275 registerNameF rega `bind` \ r_a ->
3277 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3278 instr (OpImm imm_b) (OpReg dst)
3280 returnNat (Any IntRep mkcode)
3283 = getRegister b `thenNat` \ regb ->
3284 getNewRegNCG IntRep `thenNat` \ tmp ->
3285 let revinstr_avail = maybeToBool maybe_revinstr
3286 revinstr = case maybe_revinstr of Just ri -> ri
3290 then registerCode regb dst `bind` \ code_b ->
3292 revinstr (OpImm imm_a) (OpReg dst)
3293 else registerCodeF regb `bind` \ code_b ->
3294 registerNameF regb `bind` \ r_b ->
3296 MOV L (OpReg r_b) (OpReg dst) `snocOL`
3297 revinstr (OpImm imm_a) (OpReg dst)
3301 then registerCode regb tmp `bind` \ code_b ->
3303 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3304 instr (OpReg tmp) (OpReg dst)
3305 else registerCodeF regb `bind` \ code_b ->
3306 registerNameF regb `bind` \ r_b ->
3308 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
3309 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3310 instr (OpReg tmp) (OpReg dst)
3312 returnNat (Any IntRep mkcode)
3315 = getRegister a `thenNat` \ rega ->
3316 getRegister b `thenNat` \ regb ->
3317 getNewRegNCG IntRep `thenNat` \ tmp ->
3319 = case (isAny rega, isAny regb) of
3321 -> registerCode regb tmp `bind` \ code_b ->
3322 registerCode rega dst `bind` \ code_a ->
3325 instr (OpReg tmp) (OpReg dst)
3327 -> registerCode rega tmp `bind` \ code_a ->
3328 registerCodeF regb `bind` \ code_b ->
3329 registerNameF regb `bind` \ r_b ->
3332 instr (OpReg r_b) (OpReg tmp) `snocOL`
3333 MOV L (OpReg tmp) (OpReg dst)
3335 -> registerCode regb tmp `bind` \ code_b ->
3336 registerCodeF rega `bind` \ code_a ->
3337 registerNameF rega `bind` \ r_a ->
3340 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3341 instr (OpReg tmp) (OpReg dst)
3343 -> registerCodeF rega `bind` \ code_a ->
3344 registerNameF rega `bind` \ r_a ->
3345 registerCodeF regb `bind` \ code_b ->
3346 registerNameF regb `bind` \ r_b ->
3348 MOV L (OpReg r_a) (OpReg tmp) `appOL`
3350 instr (OpReg r_b) (OpReg tmp) `snocOL`
3351 MOV L (OpReg tmp) (OpReg dst)
3353 returnNat (Any IntRep mkcode)
3356 maybe_imm_a = maybeImm a
3357 is_imm_a = maybeToBool maybe_imm_a
3358 imm_a = case maybe_imm_a of Just imm -> imm
3360 maybe_imm_b = maybeImm b
3361 is_imm_b = maybeToBool maybe_imm_b
3362 imm_b = case maybe_imm_b of Just imm -> imm
3366 trivialUCode instr x
3367 = getRegister x `thenNat` \ register ->
3369 code__2 dst = let code = registerCode register dst
3370 src = registerName register dst
3372 if isFixed register && dst /= src
3373 then toOL [MOV L (OpReg src) (OpReg dst),
3375 else unitOL (instr (OpReg src))
3377 returnNat (Any IntRep code__2)
3380 trivialFCode pk instr x y
3381 = getRegister x `thenNat` \ register1 ->
3382 getRegister y `thenNat` \ register2 ->
3383 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3384 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3386 code1 = registerCode register1 tmp1
3387 src1 = registerName register1 tmp1
3389 code2 = registerCode register2 tmp2
3390 src2 = registerName register2 tmp2
3393 -- treat the common case specially: both operands in
3395 | isAny register1 && isAny register2
3398 instr (primRepToSize pk) src1 src2 dst
3400 -- be paranoid (and inefficient)
3402 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3404 instr (primRepToSize pk) tmp1 src2 dst
3406 returnNat (Any pk code__2)
3410 trivialUFCode pk instr x
3411 = getRegister x `thenNat` \ register ->
3412 getNewRegNCG pk `thenNat` \ tmp ->
3414 code = registerCode register tmp
3415 src = registerName register tmp
3416 code__2 dst = code `snocOL` instr src dst
3418 returnNat (Any pk code__2)
3420 #endif {- i386_TARGET_ARCH -}
3422 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3424 #if sparc_TARGET_ARCH
3426 trivialCode instr x (StInt y)
3428 = getRegister x `thenNat` \ register ->
3429 getNewRegNCG IntRep `thenNat` \ tmp ->
3431 code = registerCode register tmp
3432 src1 = registerName register tmp
3433 src2 = ImmInt (fromInteger y)
3434 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3436 returnNat (Any IntRep code__2)
3438 trivialCode instr x y
3439 = getRegister x `thenNat` \ register1 ->
3440 getRegister y `thenNat` \ register2 ->
3441 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3442 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3444 code1 = registerCode register1 tmp1
3445 src1 = registerName register1 tmp1
3446 code2 = registerCode register2 tmp2
3447 src2 = registerName register2 tmp2
3448 code__2 dst = code1 `appOL` code2 `snocOL`
3449 instr src1 (RIReg src2) dst
3451 returnNat (Any IntRep code__2)
3454 trivialFCode pk instr x y
3455 = getRegister x `thenNat` \ register1 ->
3456 getRegister y `thenNat` \ register2 ->
3457 getNewRegNCG (registerRep register1)
3459 getNewRegNCG (registerRep register2)
3461 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3463 promote x = FxTOy F DF x tmp
3465 pk1 = registerRep register1
3466 code1 = registerCode register1 tmp1
3467 src1 = registerName register1 tmp1
3469 pk2 = registerRep register2
3470 code2 = registerCode register2 tmp2
3471 src2 = registerName register2 tmp2
3475 code1 `appOL` code2 `snocOL`
3476 instr (primRepToSize pk) src1 src2 dst
3477 else if pk1 == FloatRep then
3478 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3479 instr DF tmp src2 dst
3481 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3482 instr DF src1 tmp dst
3484 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3487 trivialUCode instr x
3488 = getRegister x `thenNat` \ register ->
3489 getNewRegNCG IntRep `thenNat` \ tmp ->
3491 code = registerCode register tmp
3492 src = registerName register tmp
3493 code__2 dst = code `snocOL` instr (RIReg src) dst
3495 returnNat (Any IntRep code__2)
3498 trivialUFCode pk instr x
3499 = getRegister x `thenNat` \ register ->
3500 getNewRegNCG pk `thenNat` \ tmp ->
3502 code = registerCode register tmp
3503 src = registerName register tmp
3504 code__2 dst = code `snocOL` instr src dst
3506 returnNat (Any pk code__2)
3508 #endif {- sparc_TARGET_ARCH -}
3510 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3513 %************************************************************************
3515 \subsubsection{Coercing to/from integer/floating-point...}
3517 %************************************************************************
3519 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3520 conversions. We have to store temporaries in memory to move
3521 between the integer and the floating point register sets.
3523 @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
3524 pretend, on sparc at least, that double and float regs are seperate
3525 kinds, so the value has to be computed into one kind before being
3526 explicitly "converted" to live in the other kind.
3529 coerceInt2FP :: PrimRep -> StixExpr -> NatM Register
3530 coerceFP2Int :: PrimRep -> StixExpr -> NatM Register
3532 coerceDbl2Flt :: StixExpr -> NatM Register
3533 coerceFlt2Dbl :: StixExpr -> NatM Register
3537 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3539 #if alpha_TARGET_ARCH
3542 = getRegister x `thenNat` \ register ->
3543 getNewRegNCG IntRep `thenNat` \ reg ->
3545 code = registerCode register reg
3546 src = registerName register reg
3548 code__2 dst = code . mkSeqInstrs [
3550 LD TF dst (spRel 0),
3553 returnNat (Any DoubleRep code__2)
3557 = getRegister x `thenNat` \ register ->
3558 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3560 code = registerCode register tmp
3561 src = registerName register tmp
3563 code__2 dst = code . mkSeqInstrs [
3565 ST TF tmp (spRel 0),
3568 returnNat (Any IntRep code__2)
3570 #endif {- alpha_TARGET_ARCH -}
3572 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3574 #if i386_TARGET_ARCH
3577 = getRegister x `thenNat` \ register ->
3578 getNewRegNCG IntRep `thenNat` \ reg ->
3580 code = registerCode register reg
3581 src = registerName register reg
3582 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3583 code__2 dst = code `snocOL` opc src dst
3585 returnNat (Any pk code__2)
3588 coerceFP2Int fprep x
3589 = getRegister x `thenNat` \ register ->
3590 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3592 code = registerCode register tmp
3593 src = registerName register tmp
3594 pk = registerRep register
3596 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3597 code__2 dst = code `snocOL` opc src dst
3599 returnNat (Any IntRep code__2)
3602 coerceDbl2Flt x = panic "MachCode.coerceDbl2Flt: unused on x86"
3603 coerceFlt2Dbl x = panic "MachCode.coerceFlt2Dbl: unused on x86"
3605 #endif {- i386_TARGET_ARCH -}
3607 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3609 #if sparc_TARGET_ARCH
3612 = getRegister x `thenNat` \ register ->
3613 getNewRegNCG IntRep `thenNat` \ reg ->
3615 code = registerCode register reg
3616 src = registerName register reg
3618 code__2 dst = code `appOL` toOL [
3619 ST W src (spRel (-2)),
3620 LD W (spRel (-2)) dst,
3621 FxTOy W (primRepToSize pk) dst dst]
3623 returnNat (Any pk code__2)
3626 coerceFP2Int fprep x
3627 = ASSERT(fprep == DoubleRep || fprep == FloatRep)
3628 getRegister x `thenNat` \ register ->
3629 getNewRegNCG fprep `thenNat` \ reg ->
3630 getNewRegNCG FloatRep `thenNat` \ tmp ->
3632 code = registerCode register reg
3633 src = registerName register reg
3634 code__2 dst = code `appOL` toOL [
3635 FxTOy (primRepToSize fprep) W src tmp,
3636 ST W tmp (spRel (-2)),
3637 LD W (spRel (-2)) dst]
3639 returnNat (Any IntRep code__2)
3643 = getRegister x `thenNat` \ register ->
3644 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3645 let code = registerCode register tmp
3646 src = registerName register tmp
3648 returnNat (Any FloatRep
3649 (\dst -> code `snocOL` FxTOy DF F src dst))
3653 = getRegister x `thenNat` \ register ->
3654 getNewRegNCG FloatRep `thenNat` \ tmp ->
3655 let code = registerCode register tmp
3656 src = registerName register tmp
3658 returnNat (Any DoubleRep
3659 (\dst -> code `snocOL` FxTOy F DF src dst))
3661 #endif {- sparc_TARGET_ARCH -}
3663 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -