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 )
52 import Outputable ( assertPanic )
57 @InstrBlock@s are the insn sequences generated by the insn selectors.
58 They are really trees of insns to facilitate fast appending, where a
59 left-to-right traversal (pre-order?) yields the insns in the correct
63 type InstrBlock = OrdList Instr
68 Code extractor for an entire stix tree---stix statement level.
71 stmtsToInstrs :: [StixStmt] -> NatM InstrBlock
73 = mapNat stmtToInstrs stmts `thenNat` \ instrss ->
74 returnNat (concatOL instrss)
77 stmtToInstrs :: StixStmt -> NatM InstrBlock
78 stmtToInstrs stmt = case stmt of
79 StComment s -> returnNat (unitOL (COMMENT s))
80 StSegment seg -> returnNat (unitOL (SEGMENT seg))
82 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
84 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
87 StLabel lab -> returnNat (unitOL (LABEL lab))
89 StJump dsts arg -> genJump dsts (derefDLL arg)
90 StCondJump lab arg -> genCondJump lab (derefDLL arg)
92 -- A call returning void, ie one done for its side-effects. Note
93 -- that this is the only StVoidable we handle.
94 StVoidable (StCall fn cconv VoidRep args)
95 -> genCCall fn cconv VoidRep (map derefDLL args)
97 StAssignMem pk addr src
98 | isFloatingRep pk -> assignMem_FltCode pk (derefDLL addr) (derefDLL src)
100 && is64BitRep pk -> assignMem_I64Code (derefDLL addr) (derefDLL src)
101 | otherwise -> assignMem_IntCode pk (derefDLL addr) (derefDLL src)
102 StAssignReg pk reg src
103 | isFloatingRep pk -> assignReg_FltCode pk reg (derefDLL src)
104 | ncg_target_is_32bit
105 && is64BitRep pk -> assignReg_I64Code reg (derefDLL src)
106 | otherwise -> assignReg_IntCode pk reg (derefDLL src)
109 -- When falling through on the Alpha, we still have to load pv
110 -- with the address of the next routine, so that it can load gp.
111 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
115 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
116 returnNat (DATA (primRepToSize kind) imms
117 `consOL` concatOL codes)
119 getData :: StixExpr -> NatM (InstrBlock, Imm)
120 getData (StInt i) = returnNat (nilOL, ImmInteger i)
121 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
122 getData (StFloat d) = returnNat (nilOL, ImmFloat d)
123 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
124 getData (StString s) = panic "MachCode.stmtToInstrs: unlifted StString"
125 -- the linker can handle simple arithmetic...
126 getData (StIndex rep (StCLbl lbl) (StInt off)) =
128 ImmIndex lbl (fromInteger off * getPrimRepArrayElemSize rep))
130 -- Top-level lifted-out string. The segment will already have been set
131 -- (see Stix.liftStrings).
133 -> returnNat (unitOL (ASCII True (_UNPK_ str)))
136 other -> pprPanic "stmtToInstrs" (pprStixStmt other)
139 -- Walk a Stix tree, and insert dereferences to CLabels which are marked
140 -- as labelDynamic. stmt2Instrs calls derefDLL selectively, because
141 -- not all such CLabel occurrences need this dereferencing -- SRTs don't
143 derefDLL :: StixExpr -> StixExpr
145 | opt_Static -- short out the entire deal if not doing DLLs
152 StCLbl lbl -> if labelDynamic lbl
153 then StInd PtrRep (StCLbl lbl)
155 -- all the rest are boring
156 StIndex pk base offset -> StIndex pk (qq base) (qq offset)
157 StMachOp mop args -> StMachOp mop (map qq args)
158 StInd pk addr -> StInd pk (qq addr)
159 StCall who cc pk args -> StCall who cc pk (map qq args)
165 _ -> pprPanic "derefDLL: unhandled case"
169 %************************************************************************
171 \subsection{General things for putting together code sequences}
173 %************************************************************************
176 mangleIndexTree :: StixExpr -> StixExpr
178 mangleIndexTree (StIndex pk base (StInt i))
179 = StMachOp MO_Nat_Add [base, off]
181 off = StInt (i * toInteger (getPrimRepArrayElemSize pk))
183 mangleIndexTree (StIndex pk base off)
184 = StMachOp MO_Nat_Add [
187 in if s == 0 then off
188 else StMachOp MO_Nat_Shl [off, StInt (toInteger s)]
191 shift :: PrimRep -> Int
192 shift rep = case getPrimRepArrayElemSize rep of
197 other -> pprPanic "MachCode.mangleIndexTree.shift: unhandled rep size"
198 (Outputable.int other)
202 maybeImm :: StixExpr -> Maybe Imm
206 maybeImm (StIndex rep (StCLbl l) (StInt off))
207 = Just (ImmIndex l (fromInteger off * getPrimRepArrayElemSize rep))
209 | i >= toInteger (minBound::Int) && i <= toInteger (maxBound::Int)
210 = Just (ImmInt (fromInteger i))
212 = Just (ImmInteger i)
217 %************************************************************************
219 \subsection{The @Register64@ type}
221 %************************************************************************
223 Simple support for generating 64-bit code (ie, 64 bit values and 64
224 bit assignments) on 32-bit platforms. Unlike the main code generator
225 we merely shoot for generating working code as simply as possible, and
226 pay little attention to code quality. Specifically, there is no
227 attempt to deal cleverly with the fixed-vs-floating register
228 distinction; all values are generated into (pairs of) floating
229 registers, even if this would mean some redundant reg-reg moves as a
230 result. Only one of the VRegUniques is returned, since it will be
231 of the VRegUniqueLo form, and the upper-half VReg can be determined
232 by applying getHiVRegFromLo to it.
236 data ChildCode64 -- a.k.a "Register64"
239 VRegUnique -- unique for the lower 32-bit temporary
240 -- which contains the result; use getHiVRegFromLo to find
241 -- the other VRegUnique.
242 -- Rules of this simplified insn selection game are
243 -- therefore that the returned VRegUnique may be modified
245 assignMem_I64Code :: StixExpr -> StixExpr -> NatM InstrBlock
246 assignReg_I64Code :: StixReg -> StixExpr -> NatM InstrBlock
247 iselExpr64 :: StixExpr -> NatM ChildCode64
249 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
253 assignMem_I64Code addrTree valueTree
254 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
255 getRegister addrTree `thenNat` \ register_addr ->
256 getNewRegNCG IntRep `thenNat` \ t_addr ->
257 let rlo = VirtualRegI vrlo
258 rhi = getHiVRegFromLo rlo
259 code_addr = registerCode register_addr t_addr
260 reg_addr = registerName register_addr t_addr
261 -- Little-endian store
262 mov_lo = MOV L (OpReg rlo)
263 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
264 mov_hi = MOV L (OpReg rhi)
265 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
267 returnNat (vcode `appOL` code_addr `snocOL` mov_lo `snocOL` mov_hi)
269 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
270 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
272 r_dst_lo = mkVReg u_dst IntRep
273 r_src_lo = VirtualRegI vr_src_lo
274 r_dst_hi = getHiVRegFromLo r_dst_lo
275 r_src_hi = getHiVRegFromLo r_src_lo
276 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
277 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
280 vcode `snocOL` mov_lo `snocOL` mov_hi
283 assignReg_I64Code lvalue valueTree
284 = pprPanic "assignReg_I64Code(i386): invalid lvalue"
289 iselExpr64 (StInd pk addrTree)
291 = getRegister addrTree `thenNat` \ register_addr ->
292 getNewRegNCG IntRep `thenNat` \ t_addr ->
293 getNewRegNCG IntRep `thenNat` \ rlo ->
294 let rhi = getHiVRegFromLo rlo
295 code_addr = registerCode register_addr t_addr
296 reg_addr = registerName register_addr t_addr
297 mov_lo = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
299 mov_hi = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
303 ChildCode64 (code_addr `snocOL` mov_lo `snocOL` mov_hi)
307 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
309 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
310 let r_dst_hi = getHiVRegFromLo r_dst_lo
311 r_src_lo = mkVReg vu IntRep
312 r_src_hi = getHiVRegFromLo r_src_lo
313 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
314 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
317 ChildCode64 (toOL [mov_lo, mov_hi]) (getVRegUnique r_dst_lo)
320 iselExpr64 (StCall fn cconv kind args)
322 = genCCall fn cconv kind args `thenNat` \ call ->
323 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
324 let r_dst_hi = getHiVRegFromLo r_dst_lo
325 mov_lo = MOV L (OpReg eax) (OpReg r_dst_lo)
326 mov_hi = MOV L (OpReg edx) (OpReg r_dst_hi)
329 ChildCode64 (call `snocOL` mov_lo `snocOL` mov_hi)
330 (getVRegUnique r_dst_lo)
334 = pprPanic "iselExpr64(i386)" (pprStixExpr expr)
336 #endif {- i386_TARGET_ARCH -}
338 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
340 #if sparc_TARGET_ARCH
342 assignMem_I64Code addrTree valueTree
343 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
344 getRegister addrTree `thenNat` \ register_addr ->
345 getNewRegNCG IntRep `thenNat` \ t_addr ->
346 let rlo = VirtualRegI vrlo
347 rhi = getHiVRegFromLo rlo
348 code_addr = registerCode register_addr t_addr
349 reg_addr = registerName register_addr t_addr
351 mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
352 mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
354 returnNat (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
357 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
358 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
360 r_dst_lo = mkVReg u_dst IntRep
361 r_src_lo = VirtualRegI vr_src_lo
362 r_dst_hi = getHiVRegFromLo r_dst_lo
363 r_src_hi = getHiVRegFromLo r_src_lo
364 mov_lo = mkMOV r_src_lo r_dst_lo
365 mov_hi = mkMOV r_src_hi r_dst_hi
366 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
369 vcode `snocOL` mov_hi `snocOL` mov_lo
371 assignReg_I64Code lvalue valueTree
372 = pprPanic "assignReg_I64Code(sparc): invalid lvalue"
376 -- Don't delete this -- it's very handy for debugging.
378 -- | trace ("iselExpr64: " ++ showSDoc (pprStixExpr expr)) False
379 -- = panic "iselExpr64(???)"
381 iselExpr64 (StInd pk addrTree)
383 = getRegister addrTree `thenNat` \ register_addr ->
384 getNewRegNCG IntRep `thenNat` \ t_addr ->
385 getNewRegNCG IntRep `thenNat` \ rlo ->
386 let rhi = getHiVRegFromLo rlo
387 code_addr = registerCode register_addr t_addr
388 reg_addr = registerName register_addr t_addr
389 mov_hi = LD W (AddrRegImm reg_addr (ImmInt 0)) rhi
390 mov_lo = LD W (AddrRegImm reg_addr (ImmInt 4)) rlo
393 ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo)
397 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
399 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
400 let r_dst_hi = getHiVRegFromLo r_dst_lo
401 r_src_lo = mkVReg vu IntRep
402 r_src_hi = getHiVRegFromLo r_src_lo
403 mov_lo = mkMOV r_src_lo r_dst_lo
404 mov_hi = mkMOV r_src_hi r_dst_hi
405 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
408 ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
411 iselExpr64 (StCall fn cconv kind args)
413 = genCCall fn cconv kind args `thenNat` \ call ->
414 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
415 let r_dst_hi = getHiVRegFromLo r_dst_lo
416 mov_lo = mkMOV o0 r_dst_lo
417 mov_hi = mkMOV o1 r_dst_hi
418 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
421 ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo)
422 (getVRegUnique r_dst_lo)
426 = pprPanic "iselExpr64(sparc)" (pprStixExpr expr)
428 #endif {- sparc_TARGET_ARCH -}
430 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
434 %************************************************************************
436 \subsection{The @Register@ type}
438 %************************************************************************
440 @Register@s passed up the tree. If the stix code forces the register
441 to live in a pre-decided machine register, it comes out as @Fixed@;
442 otherwise, it comes out as @Any@, and the parent can decide which
443 register to put it in.
447 = Fixed PrimRep Reg InstrBlock
448 | Any PrimRep (Reg -> InstrBlock)
450 registerCode :: Register -> Reg -> InstrBlock
451 registerCode (Fixed _ _ code) reg = code
452 registerCode (Any _ code) reg = code reg
454 registerCodeF (Fixed _ _ code) = code
455 registerCodeF (Any _ _) = panic "registerCodeF"
457 registerCodeA (Any _ code) = code
458 registerCodeA (Fixed _ _ _) = panic "registerCodeA"
460 registerName :: Register -> Reg -> Reg
461 registerName (Fixed _ reg _) _ = reg
462 registerName (Any _ _) reg = reg
464 registerNameF (Fixed _ reg _) = reg
465 registerNameF (Any _ _) = panic "registerNameF"
467 registerRep :: Register -> PrimRep
468 registerRep (Fixed pk _ _) = pk
469 registerRep (Any pk _) = pk
471 swizzleRegisterRep :: Register -> PrimRep -> Register
472 swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
473 swizzleRegisterRep (Any _ codefn) rep = Any rep codefn
475 {-# INLINE registerCode #-}
476 {-# INLINE registerCodeF #-}
477 {-# INLINE registerName #-}
478 {-# INLINE registerNameF #-}
479 {-# INLINE registerRep #-}
480 {-# INLINE isFixed #-}
483 isFixed, isAny :: Register -> Bool
484 isFixed (Fixed _ _ _) = True
485 isFixed (Any _ _) = False
487 isAny = not . isFixed
490 Generate code to get a subtree into a @Register@:
493 getRegisterReg :: StixReg -> NatM Register
494 getRegister :: StixExpr -> NatM Register
497 getRegisterReg (StixMagicId mid)
498 = case get_MagicId_reg_or_addr mid of
500 -> let pk = magicIdPrimRep mid
501 in returnNat (Fixed pk (RealReg rrno) nilOL)
503 -- By this stage, the only MagicIds remaining should be the
504 -- ones which map to a real machine register on this platform. Hence ...
505 -> pprPanic "getRegisterReg-memory" (pprMagicId mid)
507 getRegisterReg (StixTemp (StixVReg u pk))
508 = returnNat (Fixed pk (mkVReg u pk) nilOL)
512 -- Don't delete this -- it's very handy for debugging.
514 -- | trace ("getRegiste: " ++ showSDoc (pprStixExpr expr)) False
515 -- = panic "getRegister(???)"
517 getRegister (StReg reg)
520 getRegister tree@(StIndex _ _ _)
521 = getRegister (mangleIndexTree tree)
523 getRegister (StCall fn cconv kind args)
524 | not (ncg_target_is_32bit && is64BitRep kind)
525 = genCCall fn cconv kind args `thenNat` \ call ->
526 returnNat (Fixed kind reg call)
528 reg = if isFloatingRep kind
529 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
530 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
532 getRegister (StString s)
533 = getNatLabelNCG `thenNat` \ lbl ->
535 imm_lbl = ImmCLbl lbl
538 SEGMENT RoDataSegment,
540 ASCII True (_UNPK_ s),
542 #if alpha_TARGET_ARCH
543 LDA dst (AddrImm imm_lbl)
546 MOV L (OpImm imm_lbl) (OpReg dst)
548 #if sparc_TARGET_ARCH
549 SETHI (HI imm_lbl) dst,
550 OR False dst (RIImm (LO imm_lbl)) dst
554 returnNat (Any PtrRep code)
556 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
557 -- end of machine-"independent" bit; here we go on the rest...
559 #if alpha_TARGET_ARCH
561 getRegister (StDouble d)
562 = getNatLabelNCG `thenNat` \ lbl ->
563 getNewRegNCG PtrRep `thenNat` \ tmp ->
564 let code dst = mkSeqInstrs [
567 DATA TF [ImmLab (rational d)],
569 LDA tmp (AddrImm (ImmCLbl lbl)),
570 LD TF dst (AddrReg tmp)]
572 returnNat (Any DoubleRep code)
574 getRegister (StPrim primop [x]) -- unary PrimOps
576 IntNegOp -> trivialUCode (NEG Q False) x
578 NotOp -> trivialUCode NOT x
580 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
581 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
583 OrdOp -> coerceIntCode IntRep x
586 Float2IntOp -> coerceFP2Int x
587 Int2FloatOp -> coerceInt2FP pr x
588 Double2IntOp -> coerceFP2Int x
589 Int2DoubleOp -> coerceInt2FP pr x
591 Double2FloatOp -> coerceFltCode x
592 Float2DoubleOp -> coerceFltCode x
594 other_op -> getRegister (StCall fn CCallConv DoubleRep [x])
596 fn = case other_op of
597 FloatExpOp -> SLIT("exp")
598 FloatLogOp -> SLIT("log")
599 FloatSqrtOp -> SLIT("sqrt")
600 FloatSinOp -> SLIT("sin")
601 FloatCosOp -> SLIT("cos")
602 FloatTanOp -> SLIT("tan")
603 FloatAsinOp -> SLIT("asin")
604 FloatAcosOp -> SLIT("acos")
605 FloatAtanOp -> SLIT("atan")
606 FloatSinhOp -> SLIT("sinh")
607 FloatCoshOp -> SLIT("cosh")
608 FloatTanhOp -> SLIT("tanh")
609 DoubleExpOp -> SLIT("exp")
610 DoubleLogOp -> SLIT("log")
611 DoubleSqrtOp -> SLIT("sqrt")
612 DoubleSinOp -> SLIT("sin")
613 DoubleCosOp -> SLIT("cos")
614 DoubleTanOp -> SLIT("tan")
615 DoubleAsinOp -> SLIT("asin")
616 DoubleAcosOp -> SLIT("acos")
617 DoubleAtanOp -> SLIT("atan")
618 DoubleSinhOp -> SLIT("sinh")
619 DoubleCoshOp -> SLIT("cosh")
620 DoubleTanhOp -> SLIT("tanh")
622 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
624 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
626 CharGtOp -> trivialCode (CMP LTT) y x
627 CharGeOp -> trivialCode (CMP LE) y x
628 CharEqOp -> trivialCode (CMP EQQ) x y
629 CharNeOp -> int_NE_code x y
630 CharLtOp -> trivialCode (CMP LTT) x y
631 CharLeOp -> trivialCode (CMP LE) x y
633 IntGtOp -> trivialCode (CMP LTT) y x
634 IntGeOp -> trivialCode (CMP LE) y x
635 IntEqOp -> trivialCode (CMP EQQ) x y
636 IntNeOp -> int_NE_code x y
637 IntLtOp -> trivialCode (CMP LTT) x y
638 IntLeOp -> trivialCode (CMP LE) x y
640 WordGtOp -> trivialCode (CMP ULT) y x
641 WordGeOp -> trivialCode (CMP ULE) x y
642 WordEqOp -> trivialCode (CMP EQQ) x y
643 WordNeOp -> int_NE_code x y
644 WordLtOp -> trivialCode (CMP ULT) x y
645 WordLeOp -> trivialCode (CMP ULE) x y
647 AddrGtOp -> trivialCode (CMP ULT) y x
648 AddrGeOp -> trivialCode (CMP ULE) y x
649 AddrEqOp -> trivialCode (CMP EQQ) x y
650 AddrNeOp -> int_NE_code x y
651 AddrLtOp -> trivialCode (CMP ULT) x y
652 AddrLeOp -> trivialCode (CMP ULE) x y
654 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
655 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
656 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
657 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
658 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
659 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
661 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
662 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
663 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
664 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
665 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
666 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
668 IntAddOp -> trivialCode (ADD Q False) x y
669 IntSubOp -> trivialCode (SUB Q False) x y
670 IntMulOp -> trivialCode (MUL Q False) x y
671 IntQuotOp -> trivialCode (DIV Q False) x y
672 IntRemOp -> trivialCode (REM Q False) x y
674 WordAddOp -> trivialCode (ADD Q False) x y
675 WordSubOp -> trivialCode (SUB Q False) x y
676 WordMulOp -> trivialCode (MUL Q False) x y
677 WordQuotOp -> trivialCode (DIV Q True) x y
678 WordRemOp -> trivialCode (REM Q True) x y
680 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
681 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
682 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
683 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
685 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
686 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
687 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
688 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
690 AddrAddOp -> trivialCode (ADD Q False) x y
691 AddrSubOp -> trivialCode (SUB Q False) x y
692 AddrRemOp -> trivialCode (REM Q True) x y
694 AndOp -> trivialCode AND x y
695 OrOp -> trivialCode OR x y
696 XorOp -> trivialCode XOR x y
697 SllOp -> trivialCode SLL x y
698 SrlOp -> trivialCode SRL x y
700 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
701 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
702 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
704 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
705 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
707 {- ------------------------------------------------------------
708 Some bizarre special code for getting condition codes into
709 registers. Integer non-equality is a test for equality
710 followed by an XOR with 1. (Integer comparisons always set
711 the result register to 0 or 1.) Floating point comparisons of
712 any kind leave the result in a floating point register, so we
713 need to wrangle an integer register out of things.
715 int_NE_code :: StixTree -> StixTree -> NatM Register
718 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
719 getNewRegNCG IntRep `thenNat` \ tmp ->
721 code = registerCode register tmp
722 src = registerName register tmp
723 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
725 returnNat (Any IntRep code__2)
727 {- ------------------------------------------------------------
728 Comments for int_NE_code also apply to cmpF_code
731 :: (Reg -> Reg -> Reg -> Instr)
733 -> StixTree -> StixTree
736 cmpF_code instr cond x y
737 = trivialFCode pr instr x y `thenNat` \ register ->
738 getNewRegNCG DoubleRep `thenNat` \ tmp ->
739 getNatLabelNCG `thenNat` \ lbl ->
741 code = registerCode register tmp
742 result = registerName register tmp
744 code__2 dst = code . mkSeqInstrs [
745 OR zeroh (RIImm (ImmInt 1)) dst,
746 BF cond result (ImmCLbl lbl),
747 OR zeroh (RIReg zeroh) dst,
750 returnNat (Any IntRep code__2)
752 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
753 ------------------------------------------------------------
755 getRegister (StInd pk mem)
756 = getAmode mem `thenNat` \ amode ->
758 code = amodeCode amode
759 src = amodeAddr amode
760 size = primRepToSize pk
761 code__2 dst = code . mkSeqInstr (LD size dst src)
763 returnNat (Any pk code__2)
765 getRegister (StInt i)
768 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
770 returnNat (Any IntRep code)
773 code dst = mkSeqInstr (LDI Q dst src)
775 returnNat (Any IntRep code)
777 src = ImmInt (fromInteger i)
782 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
784 returnNat (Any PtrRep code)
787 imm__2 = case imm of Just x -> x
789 #endif {- alpha_TARGET_ARCH -}
791 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
795 getRegister (StFloat f)
796 = getNatLabelNCG `thenNat` \ lbl ->
797 let code dst = toOL [
802 GLD F (ImmAddr (ImmCLbl lbl) 0) dst
805 returnNat (Any FloatRep code)
808 getRegister (StDouble d)
811 = let code dst = unitOL (GLDZ dst)
812 in returnNat (Any DoubleRep code)
815 = let code dst = unitOL (GLD1 dst)
816 in returnNat (Any DoubleRep code)
819 = getNatLabelNCG `thenNat` \ lbl ->
820 let code dst = toOL [
823 DATA DF [ImmDouble d],
825 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
828 returnNat (Any DoubleRep code)
831 getRegister (StMachOp mop [x]) -- unary MachOps
833 MO_NatS_Neg -> trivialUCode (NEGI L) x
834 MO_Nat_Not -> trivialUCode (NOT L) x
835 MO_32U_to_8U -> trivialUCode (AND L (OpImm (ImmInt 255))) x
837 MO_Flt_Neg -> trivialUFCode FloatRep (GNEG F) x
838 MO_Dbl_Neg -> trivialUFCode DoubleRep (GNEG DF) x
840 MO_Flt_Sqrt -> trivialUFCode FloatRep (GSQRT F) x
841 MO_Dbl_Sqrt -> trivialUFCode DoubleRep (GSQRT DF) x
843 MO_Flt_Sin -> trivialUFCode FloatRep (GSIN F) x
844 MO_Dbl_Sin -> trivialUFCode DoubleRep (GSIN DF) x
846 MO_Flt_Cos -> trivialUFCode FloatRep (GCOS F) x
847 MO_Dbl_Cos -> trivialUFCode DoubleRep (GCOS DF) x
849 MO_Flt_Tan -> trivialUFCode FloatRep (GTAN F) x
850 MO_Dbl_Tan -> trivialUFCode DoubleRep (GTAN DF) x
852 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
853 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
854 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
855 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
857 -- Conversions which are a nop on x86
858 MO_NatS_to_32U -> conversionNop WordRep x
859 MO_32U_to_NatS -> conversionNop IntRep x
861 MO_NatU_to_NatS -> conversionNop IntRep x
862 MO_NatS_to_NatU -> conversionNop WordRep x
863 MO_NatP_to_NatU -> conversionNop WordRep x
864 MO_NatU_to_NatP -> conversionNop PtrRep x
865 MO_NatS_to_NatP -> conversionNop PtrRep x
866 MO_NatP_to_NatS -> conversionNop IntRep x
868 MO_Dbl_to_Flt -> conversionNop FloatRep x
869 MO_Flt_to_Dbl -> conversionNop DoubleRep x
871 -- sign-extending widenings
872 MO_8U_to_NatU -> integerExtend False 24 x
873 MO_8S_to_NatS -> integerExtend True 24 x
874 MO_16U_to_NatU -> integerExtend False 16 x
875 MO_16S_to_NatS -> integerExtend True 16 x
876 MO_8U_to_32U -> integerExtend False 24 x
880 (if is_float_op then demote else id)
881 (StCall fn CCallConv DoubleRep
882 [(if is_float_op then promote else id) x])
885 integerExtend signed nBits x
887 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
888 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
891 conversionNop new_rep expr
892 = getRegister expr `thenNat` \ e_code ->
893 returnNat (swizzleRegisterRep e_code new_rep)
895 promote x = StMachOp MO_Flt_to_Dbl [x]
896 demote x = StMachOp MO_Dbl_to_Flt [x]
899 MO_Flt_Exp -> (True, SLIT("exp"))
900 MO_Flt_Log -> (True, SLIT("log"))
902 MO_Flt_Asin -> (True, SLIT("asin"))
903 MO_Flt_Acos -> (True, SLIT("acos"))
904 MO_Flt_Atan -> (True, SLIT("atan"))
906 MO_Flt_Sinh -> (True, SLIT("sinh"))
907 MO_Flt_Cosh -> (True, SLIT("cosh"))
908 MO_Flt_Tanh -> (True, SLIT("tanh"))
910 MO_Dbl_Exp -> (False, SLIT("exp"))
911 MO_Dbl_Log -> (False, SLIT("log"))
913 MO_Dbl_Asin -> (False, SLIT("asin"))
914 MO_Dbl_Acos -> (False, SLIT("acos"))
915 MO_Dbl_Atan -> (False, SLIT("atan"))
917 MO_Dbl_Sinh -> (False, SLIT("sinh"))
918 MO_Dbl_Cosh -> (False, SLIT("cosh"))
919 MO_Dbl_Tanh -> (False, SLIT("tanh"))
921 other -> pprPanic "getRegister(x86) - binary StMachOp (2)"
925 getRegister (StMachOp mop [x, y]) -- dyadic MachOps
927 MO_32U_Gt -> condIntReg GTT x y
928 MO_32U_Ge -> condIntReg GE x y
929 MO_32U_Eq -> condIntReg EQQ x y
930 MO_32U_Ne -> condIntReg NE x y
931 MO_32U_Lt -> condIntReg LTT x y
932 MO_32U_Le -> condIntReg LE x y
934 MO_Nat_Eq -> condIntReg EQQ x y
935 MO_Nat_Ne -> condIntReg NE x y
937 MO_NatS_Gt -> condIntReg GTT x y
938 MO_NatS_Ge -> condIntReg GE x y
939 MO_NatS_Lt -> condIntReg LTT x y
940 MO_NatS_Le -> condIntReg LE x y
942 MO_NatU_Gt -> condIntReg GU x y
943 MO_NatU_Ge -> condIntReg GEU x y
944 MO_NatU_Lt -> condIntReg LU x y
945 MO_NatU_Le -> condIntReg LEU x y
947 MO_Flt_Gt -> condFltReg GTT x y
948 MO_Flt_Ge -> condFltReg GE x y
949 MO_Flt_Eq -> condFltReg EQQ x y
950 MO_Flt_Ne -> condFltReg NE x y
951 MO_Flt_Lt -> condFltReg LTT x y
952 MO_Flt_Le -> condFltReg LE x y
954 MO_Dbl_Gt -> condFltReg GTT x y
955 MO_Dbl_Ge -> condFltReg GE x y
956 MO_Dbl_Eq -> condFltReg EQQ x y
957 MO_Dbl_Ne -> condFltReg NE x y
958 MO_Dbl_Lt -> condFltReg LTT x y
959 MO_Dbl_Le -> condFltReg LE x y
961 MO_Nat_Add -> add_code L x y
962 MO_Nat_Sub -> sub_code L x y
963 MO_NatS_Quot -> trivialCode (IQUOT L) Nothing x y
964 MO_NatS_Rem -> trivialCode (IREM L) Nothing x y
965 MO_NatU_Quot -> trivialCode (QUOT L) Nothing x y
966 MO_NatU_Rem -> trivialCode (REM L) Nothing x y
967 MO_NatS_Mul -> let op = IMUL L in trivialCode op (Just op) x y
968 MO_NatU_Mul -> let op = MUL L in trivialCode op (Just op) x y
969 MO_NatS_MulMayOflo -> imulMayOflo x y
971 MO_Flt_Add -> trivialFCode FloatRep GADD x y
972 MO_Flt_Sub -> trivialFCode FloatRep GSUB x y
973 MO_Flt_Mul -> trivialFCode FloatRep GMUL x y
974 MO_Flt_Div -> trivialFCode FloatRep GDIV x y
976 MO_Dbl_Add -> trivialFCode DoubleRep GADD x y
977 MO_Dbl_Sub -> trivialFCode DoubleRep GSUB x y
978 MO_Dbl_Mul -> trivialFCode DoubleRep GMUL x y
979 MO_Dbl_Div -> trivialFCode DoubleRep GDIV x y
981 MO_Nat_And -> let op = AND L in trivialCode op (Just op) x y
982 MO_Nat_Or -> let op = OR L in trivialCode op (Just op) x y
983 MO_Nat_Xor -> let op = XOR L in trivialCode op (Just op) x y
985 {- Shift ops on x86s have constraints on their source, it
986 either has to be Imm, CL or 1
987 => trivialCode's is not restrictive enough (sigh.)
989 MO_Nat_Shl -> shift_code (SHL L) x y {-False-}
990 MO_Nat_Shr -> shift_code (SHR L) x y {-False-}
991 MO_Nat_Sar -> shift_code (SAR L) x y {-False-}
993 MO_Flt_Pwr -> getRegister (demote
994 (StCall SLIT("pow") CCallConv DoubleRep
995 [promote x, promote y])
997 MO_Dbl_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
999 other -> pprPanic "getRegister(x86) - binary StMachOp (1)" (pprMachOp mop)
1001 promote x = StMachOp MO_Flt_to_Dbl [x]
1002 demote x = StMachOp MO_Dbl_to_Flt [x]
1004 --------------------
1005 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1007 = getNewRegNCG IntRep `thenNat` \ t1 ->
1008 getNewRegNCG IntRep `thenNat` \ t2 ->
1009 getNewRegNCG IntRep `thenNat` \ res_lo ->
1010 getNewRegNCG IntRep `thenNat` \ res_hi ->
1011 getRegister a1 `thenNat` \ reg1 ->
1012 getRegister a2 `thenNat` \ reg2 ->
1013 let code1 = registerCode reg1 t1
1014 code2 = registerCode reg2 t2
1015 src1 = registerName reg1 t1
1016 src2 = registerName reg2 t2
1017 code dst = code1 `appOL` code2 `appOL`
1019 MOV L (OpReg src1) (OpReg res_hi),
1020 MOV L (OpReg src2) (OpReg res_lo),
1021 IMUL64 res_hi res_lo, -- result in res_hi:res_lo
1022 SAR L (ImmInt 31) (OpReg res_lo), -- sign extend lower part
1023 SUB L (OpReg res_hi) (OpReg res_lo), -- compare against upper
1024 MOV L (OpReg res_lo) (OpReg dst)
1025 -- dst==0 if high part == sign extended low part
1028 returnNat (Any IntRep code)
1030 --------------------
1031 shift_code :: (Imm -> Operand -> Instr)
1036 {- Case1: shift length as immediate -}
1037 -- Code is the same as the first eq. for trivialCode -- sigh.
1038 shift_code instr x y{-amount-}
1040 = getRegister x `thenNat` \ regx ->
1043 then registerCodeA regx dst `bind` \ code_x ->
1045 instr imm__2 (OpReg dst)
1046 else registerCodeF regx `bind` \ code_x ->
1047 registerNameF regx `bind` \ r_x ->
1049 MOV L (OpReg r_x) (OpReg dst) `snocOL`
1050 instr imm__2 (OpReg dst)
1052 returnNat (Any IntRep mkcode)
1055 imm__2 = case imm of Just x -> x
1057 {- Case2: shift length is complex (non-immediate) -}
1058 -- Since ECX is always used as a spill temporary, we can't
1059 -- use it here to do non-immediate shifts. No big deal --
1060 -- they are only very rare, and we can use an equivalent
1061 -- test-and-jump sequence which doesn't use ECX.
1062 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
1063 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
1064 shift_code instr x y{-amount-}
1065 = getRegister x `thenNat` \ register1 ->
1066 getRegister y `thenNat` \ register2 ->
1067 getNatLabelNCG `thenNat` \ lbl_test3 ->
1068 getNatLabelNCG `thenNat` \ lbl_test2 ->
1069 getNatLabelNCG `thenNat` \ lbl_test1 ->
1070 getNatLabelNCG `thenNat` \ lbl_test0 ->
1071 getNatLabelNCG `thenNat` \ lbl_after ->
1072 getNewRegNCG IntRep `thenNat` \ tmp ->
1074 = let src_val = registerName register1 dst
1075 code_val = registerCode register1 dst
1076 src_amt = registerName register2 tmp
1077 code_amt = registerCode register2 tmp
1082 MOV L (OpReg src_amt) r_tmp `appOL`
1084 MOV L (OpReg src_val) r_dst `appOL`
1086 COMMENT (_PK_ "begin shift sequence"),
1087 MOV L (OpReg src_val) r_dst,
1088 MOV L (OpReg src_amt) r_tmp,
1090 BT L (ImmInt 4) r_tmp,
1092 instr (ImmInt 16) r_dst,
1095 BT L (ImmInt 3) r_tmp,
1097 instr (ImmInt 8) r_dst,
1100 BT L (ImmInt 2) r_tmp,
1102 instr (ImmInt 4) r_dst,
1105 BT L (ImmInt 1) r_tmp,
1107 instr (ImmInt 2) r_dst,
1110 BT L (ImmInt 0) r_tmp,
1112 instr (ImmInt 1) r_dst,
1115 COMMENT (_PK_ "end shift sequence")
1118 returnNat (Any IntRep code__2)
1120 --------------------
1121 add_code :: Size -> StixExpr -> StixExpr -> NatM Register
1123 add_code sz x (StInt y)
1124 = getRegister x `thenNat` \ register ->
1125 getNewRegNCG IntRep `thenNat` \ tmp ->
1127 code = registerCode register tmp
1128 src1 = registerName register tmp
1129 src2 = ImmInt (fromInteger y)
1132 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1135 returnNat (Any IntRep code__2)
1137 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
1139 --------------------
1140 sub_code :: Size -> StixExpr -> StixExpr -> NatM Register
1142 sub_code sz x (StInt y)
1143 = getRegister x `thenNat` \ register ->
1144 getNewRegNCG IntRep `thenNat` \ tmp ->
1146 code = registerCode register tmp
1147 src1 = registerName register tmp
1148 src2 = ImmInt (-(fromInteger y))
1151 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1154 returnNat (Any IntRep code__2)
1156 sub_code sz x y = trivialCode (SUB sz) Nothing x y
1158 getRegister (StInd pk mem)
1159 | not (is64BitRep pk)
1160 = getAmode mem `thenNat` \ amode ->
1162 code = amodeCode amode
1163 src = amodeAddr amode
1164 size = primRepToSize pk
1165 code__2 dst = code `snocOL`
1166 if pk == DoubleRep || pk == FloatRep
1167 then GLD size src dst
1175 (OpAddr src) (OpReg dst)
1177 returnNat (Any pk code__2)
1179 getRegister (StInt i)
1181 src = ImmInt (fromInteger i)
1184 = unitOL (XOR L (OpReg dst) (OpReg dst))
1186 = unitOL (MOV L (OpImm src) (OpReg dst))
1188 returnNat (Any IntRep code)
1192 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
1194 returnNat (Any PtrRep code)
1196 = ncgPrimopMoan "getRegister(x86)" (pprStixExpr leaf)
1199 imm__2 = case imm of Just x -> x
1201 #endif {- i386_TARGET_ARCH -}
1203 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1205 #if sparc_TARGET_ARCH
1207 getRegister (StFloat d)
1208 = getNatLabelNCG `thenNat` \ lbl ->
1209 getNewRegNCG PtrRep `thenNat` \ tmp ->
1210 let code dst = toOL [
1211 SEGMENT DataSegment,
1213 DATA F [ImmFloat d],
1214 SEGMENT TextSegment,
1215 SETHI (HI (ImmCLbl lbl)) tmp,
1216 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1218 returnNat (Any FloatRep code)
1220 getRegister (StDouble d)
1221 = getNatLabelNCG `thenNat` \ lbl ->
1222 getNewRegNCG PtrRep `thenNat` \ tmp ->
1223 let code dst = toOL [
1224 SEGMENT DataSegment,
1226 DATA DF [ImmDouble d],
1227 SEGMENT TextSegment,
1228 SETHI (HI (ImmCLbl lbl)) tmp,
1229 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1231 returnNat (Any DoubleRep code)
1234 getRegister (StMachOp mop [x]) -- unary PrimOps
1236 MO_NatS_Neg -> trivialUCode (SUB False False g0) x
1237 MO_Nat_Not -> trivialUCode (XNOR False g0) x
1239 MO_Flt_Neg -> trivialUFCode FloatRep (FNEG F) x
1240 MO_Dbl_Neg -> trivialUFCode DoubleRep (FNEG DF) x
1242 MO_Dbl_to_Flt -> coerceDbl2Flt x
1243 MO_Flt_to_Dbl -> coerceFlt2Dbl x
1245 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
1246 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
1247 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
1248 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
1250 -- Conversions which are a nop on sparc
1251 MO_32U_to_NatS -> conversionNop IntRep x
1252 MO_NatS_to_32U -> conversionNop WordRep x
1254 MO_NatU_to_NatS -> conversionNop IntRep x
1255 MO_NatS_to_NatU -> conversionNop WordRep x
1256 MO_NatP_to_NatU -> conversionNop WordRep x
1257 MO_NatU_to_NatP -> conversionNop PtrRep x
1258 MO_NatS_to_NatP -> conversionNop PtrRep x
1259 MO_NatP_to_NatS -> conversionNop IntRep x
1261 -- sign-extending widenings
1262 MO_8U_to_NatU -> integerExtend False 24 x
1263 MO_8S_to_NatS -> integerExtend True 24 x
1264 MO_16U_to_NatU -> integerExtend False 16 x
1265 MO_16S_to_NatS -> integerExtend True 16 x
1268 let fixed_x = if is_float_op -- promote to double
1269 then StMachOp MO_Flt_to_Dbl [x]
1272 getRegister (StCall fn CCallConv DoubleRep [fixed_x])
1274 integerExtend signed nBits x
1276 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
1277 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
1279 conversionNop new_rep expr
1280 = getRegister expr `thenNat` \ e_code ->
1281 returnNat (swizzleRegisterRep e_code new_rep)
1285 MO_Flt_Exp -> (True, SLIT("exp"))
1286 MO_Flt_Log -> (True, SLIT("log"))
1287 MO_Flt_Sqrt -> (True, SLIT("sqrt"))
1289 MO_Flt_Sin -> (True, SLIT("sin"))
1290 MO_Flt_Cos -> (True, SLIT("cos"))
1291 MO_Flt_Tan -> (True, SLIT("tan"))
1293 MO_Flt_Asin -> (True, SLIT("asin"))
1294 MO_Flt_Acos -> (True, SLIT("acos"))
1295 MO_Flt_Atan -> (True, SLIT("atan"))
1297 MO_Flt_Sinh -> (True, SLIT("sinh"))
1298 MO_Flt_Cosh -> (True, SLIT("cosh"))
1299 MO_Flt_Tanh -> (True, SLIT("tanh"))
1301 MO_Dbl_Exp -> (False, SLIT("exp"))
1302 MO_Dbl_Log -> (False, SLIT("log"))
1303 MO_Dbl_Sqrt -> (False, SLIT("sqrt"))
1305 MO_Dbl_Sin -> (False, SLIT("sin"))
1306 MO_Dbl_Cos -> (False, SLIT("cos"))
1307 MO_Dbl_Tan -> (False, SLIT("tan"))
1309 MO_Dbl_Asin -> (False, SLIT("asin"))
1310 MO_Dbl_Acos -> (False, SLIT("acos"))
1311 MO_Dbl_Atan -> (False, SLIT("atan"))
1313 MO_Dbl_Sinh -> (False, SLIT("sinh"))
1314 MO_Dbl_Cosh -> (False, SLIT("cosh"))
1315 MO_Dbl_Tanh -> (False, SLIT("tanh"))
1317 other -> pprPanic "getRegister(sparc) - binary StMachOp (2)"
1321 getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
1323 MO_32U_Gt -> condIntReg GTT x y
1324 MO_32U_Ge -> condIntReg GE x y
1325 MO_32U_Eq -> condIntReg EQQ x y
1326 MO_32U_Ne -> condIntReg NE x y
1327 MO_32U_Lt -> condIntReg LTT x y
1328 MO_32U_Le -> condIntReg LE x y
1330 MO_Nat_Eq -> condIntReg EQQ x y
1331 MO_Nat_Ne -> condIntReg NE x y
1333 MO_NatS_Gt -> condIntReg GTT x y
1334 MO_NatS_Ge -> condIntReg GE x y
1335 MO_NatS_Lt -> condIntReg LTT x y
1336 MO_NatS_Le -> condIntReg LE x y
1338 MO_NatU_Gt -> condIntReg GU x y
1339 MO_NatU_Ge -> condIntReg GEU x y
1340 MO_NatU_Lt -> condIntReg LU x y
1341 MO_NatU_Le -> condIntReg LEU x y
1343 MO_Flt_Gt -> condFltReg GTT x y
1344 MO_Flt_Ge -> condFltReg GE x y
1345 MO_Flt_Eq -> condFltReg EQQ x y
1346 MO_Flt_Ne -> condFltReg NE x y
1347 MO_Flt_Lt -> condFltReg LTT x y
1348 MO_Flt_Le -> condFltReg LE x y
1350 MO_Dbl_Gt -> condFltReg GTT x y
1351 MO_Dbl_Ge -> condFltReg GE x y
1352 MO_Dbl_Eq -> condFltReg EQQ x y
1353 MO_Dbl_Ne -> condFltReg NE x y
1354 MO_Dbl_Lt -> condFltReg LTT x y
1355 MO_Dbl_Le -> condFltReg LE x y
1357 MO_Nat_Add -> trivialCode (ADD False False) x y
1358 MO_Nat_Sub -> trivialCode (SUB False False) x y
1360 MO_NatS_Mul -> trivialCode (SMUL False) x y
1361 MO_NatU_Mul -> trivialCode (UMUL False) x y
1362 MO_NatS_MulMayOflo -> imulMayOflo x y
1364 -- ToDo: teach about V8+ SPARC div instructions
1365 MO_NatS_Quot -> idiv SLIT(".div") x y
1366 MO_NatS_Rem -> idiv SLIT(".rem") x y
1367 MO_NatU_Quot -> idiv SLIT(".udiv") x y
1368 MO_NatU_Rem -> idiv SLIT(".urem") x y
1370 MO_Flt_Add -> trivialFCode FloatRep FADD x y
1371 MO_Flt_Sub -> trivialFCode FloatRep FSUB x y
1372 MO_Flt_Mul -> trivialFCode FloatRep FMUL x y
1373 MO_Flt_Div -> trivialFCode FloatRep FDIV x y
1375 MO_Dbl_Add -> trivialFCode DoubleRep FADD x y
1376 MO_Dbl_Sub -> trivialFCode DoubleRep FSUB x y
1377 MO_Dbl_Mul -> trivialFCode DoubleRep FMUL x y
1378 MO_Dbl_Div -> trivialFCode DoubleRep FDIV x y
1380 MO_Nat_And -> trivialCode (AND False) x y
1381 MO_Nat_Or -> trivialCode (OR False) x y
1382 MO_Nat_Xor -> trivialCode (XOR False) x y
1384 MO_Nat_Shl -> trivialCode SLL x y
1385 MO_Nat_Shr -> trivialCode SRL x y
1386 MO_Nat_Sar -> trivialCode SRA x y
1388 MO_Flt_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1389 [promote x, promote y])
1390 where promote x = StMachOp MO_Flt_to_Dbl [x]
1391 MO_Dbl_Pwr -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1394 other -> pprPanic "getRegister(sparc) - binary StMachOp (1)" (pprMachOp mop)
1396 idiv fn x y = getRegister (StCall fn CCallConv IntRep [x, y])
1398 --------------------
1399 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1401 = getNewRegNCG IntRep `thenNat` \ t1 ->
1402 getNewRegNCG IntRep `thenNat` \ t2 ->
1403 getNewRegNCG IntRep `thenNat` \ res_lo ->
1404 getNewRegNCG IntRep `thenNat` \ res_hi ->
1405 getRegister a1 `thenNat` \ reg1 ->
1406 getRegister a2 `thenNat` \ reg2 ->
1407 let code1 = registerCode reg1 t1
1408 code2 = registerCode reg2 t2
1409 src1 = registerName reg1 t1
1410 src2 = registerName reg2 t2
1411 code dst = code1 `appOL` code2 `appOL`
1413 SMUL False src1 (RIReg src2) res_lo,
1415 SRA res_lo (RIImm (ImmInt 31)) res_lo,
1416 SUB False False res_lo (RIReg res_hi) dst
1419 returnNat (Any IntRep code)
1421 getRegister (StInd pk mem)
1422 = getAmode mem `thenNat` \ amode ->
1424 code = amodeCode amode
1425 src = amodeAddr amode
1426 size = primRepToSize pk
1427 code__2 dst = code `snocOL` LD size src dst
1429 returnNat (Any pk code__2)
1431 getRegister (StInt i)
1434 src = ImmInt (fromInteger i)
1435 code dst = unitOL (OR False g0 (RIImm src) dst)
1437 returnNat (Any IntRep code)
1443 SETHI (HI imm__2) dst,
1444 OR False dst (RIImm (LO imm__2)) dst]
1446 returnNat (Any PtrRep code)
1448 = ncgPrimopMoan "getRegister(sparc)" (pprStixExpr leaf)
1451 imm__2 = case imm of Just x -> x
1453 #endif {- sparc_TARGET_ARCH -}
1455 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1459 %************************************************************************
1461 \subsection{The @Amode@ type}
1463 %************************************************************************
1465 @Amode@s: Memory addressing modes passed up the tree.
1467 data Amode = Amode MachRegsAddr InstrBlock
1469 amodeAddr (Amode addr _) = addr
1470 amodeCode (Amode _ code) = code
1473 Now, given a tree (the argument to an StInd) that references memory,
1474 produce a suitable addressing mode.
1476 A Rule of the Game (tm) for Amodes: use of the addr bit must
1477 immediately follow use of the code part, since the code part puts
1478 values in registers which the addr then refers to. So you can't put
1479 anything in between, lest it overwrite some of those registers. If
1480 you need to do some other computation between the code part and use of
1481 the addr bit, first store the effective address from the amode in a
1482 temporary, then do the other computation, and then use the temporary:
1486 ... other computation ...
1490 getAmode :: StixExpr -> NatM Amode
1492 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1494 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1496 #if alpha_TARGET_ARCH
1498 getAmode (StPrim IntSubOp [x, StInt i])
1499 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1500 getRegister x `thenNat` \ register ->
1502 code = registerCode register tmp
1503 reg = registerName register tmp
1504 off = ImmInt (-(fromInteger i))
1506 returnNat (Amode (AddrRegImm reg off) code)
1508 getAmode (StPrim IntAddOp [x, StInt i])
1509 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1510 getRegister x `thenNat` \ register ->
1512 code = registerCode register tmp
1513 reg = registerName register tmp
1514 off = ImmInt (fromInteger i)
1516 returnNat (Amode (AddrRegImm reg off) code)
1520 = returnNat (Amode (AddrImm imm__2) id)
1523 imm__2 = case imm of Just x -> x
1526 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1527 getRegister other `thenNat` \ register ->
1529 code = registerCode register tmp
1530 reg = registerName register tmp
1532 returnNat (Amode (AddrReg reg) code)
1534 #endif {- alpha_TARGET_ARCH -}
1536 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1538 #if i386_TARGET_ARCH
1540 -- This is all just ridiculous, since it carefully undoes
1541 -- what mangleIndexTree has just done.
1542 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1543 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1544 getRegister x `thenNat` \ register ->
1546 code = registerCode register tmp
1547 reg = registerName register tmp
1548 off = ImmInt (-(fromInteger i))
1550 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1552 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1554 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1557 imm__2 = case imm of Just x -> x
1559 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1560 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1561 getRegister x `thenNat` \ register ->
1563 code = registerCode register tmp
1564 reg = registerName register tmp
1565 off = ImmInt (fromInteger i)
1567 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1569 getAmode (StMachOp MO_Nat_Add [x, StMachOp MO_Nat_Shl [y, StInt shift]])
1570 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1571 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1572 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1573 getRegister x `thenNat` \ register1 ->
1574 getRegister y `thenNat` \ register2 ->
1576 code1 = registerCode register1 tmp1
1577 reg1 = registerName register1 tmp1
1578 code2 = registerCode register2 tmp2
1579 reg2 = registerName register2 tmp2
1580 code__2 = code1 `appOL` code2
1581 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1583 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1588 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1591 imm__2 = case imm of Just x -> x
1594 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1595 getRegister other `thenNat` \ register ->
1597 code = registerCode register tmp
1598 reg = registerName register tmp
1600 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1602 #endif {- i386_TARGET_ARCH -}
1604 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1606 #if sparc_TARGET_ARCH
1608 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1610 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1611 getRegister x `thenNat` \ register ->
1613 code = registerCode register tmp
1614 reg = registerName register tmp
1615 off = ImmInt (-(fromInteger i))
1617 returnNat (Amode (AddrRegImm reg off) code)
1620 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1622 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1623 getRegister x `thenNat` \ register ->
1625 code = registerCode register tmp
1626 reg = registerName register tmp
1627 off = ImmInt (fromInteger i)
1629 returnNat (Amode (AddrRegImm reg off) code)
1631 getAmode (StMachOp MO_Nat_Add [x, y])
1632 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1633 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1634 getRegister x `thenNat` \ register1 ->
1635 getRegister y `thenNat` \ register2 ->
1637 code1 = registerCode register1 tmp1
1638 reg1 = registerName register1 tmp1
1639 code2 = registerCode register2 tmp2
1640 reg2 = registerName register2 tmp2
1641 code__2 = code1 `appOL` code2
1643 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1647 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1649 code = unitOL (SETHI (HI imm__2) tmp)
1651 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1654 imm__2 = case imm of Just x -> x
1657 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1658 getRegister other `thenNat` \ register ->
1660 code = registerCode register tmp
1661 reg = registerName register tmp
1664 returnNat (Amode (AddrRegImm reg off) code)
1666 #endif {- sparc_TARGET_ARCH -}
1668 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1671 %************************************************************************
1673 \subsection{The @CondCode@ type}
1675 %************************************************************************
1677 Condition codes passed up the tree.
1679 data CondCode = CondCode Bool Cond InstrBlock
1681 condName (CondCode _ cond _) = cond
1682 condFloat (CondCode is_float _ _) = is_float
1683 condCode (CondCode _ _ code) = code
1686 Set up a condition code for a conditional branch.
1689 getCondCode :: StixExpr -> NatM CondCode
1691 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1693 #if alpha_TARGET_ARCH
1694 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1695 #endif {- alpha_TARGET_ARCH -}
1697 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1699 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1700 -- yes, they really do seem to want exactly the same!
1702 getCondCode (StMachOp mop [x, y])
1704 MO_32U_Gt -> condIntCode GTT x y
1705 MO_32U_Ge -> condIntCode GE x y
1706 MO_32U_Eq -> condIntCode EQQ x y
1707 MO_32U_Ne -> condIntCode NE x y
1708 MO_32U_Lt -> condIntCode LTT x y
1709 MO_32U_Le -> condIntCode LE x y
1711 MO_Nat_Eq -> condIntCode EQQ x y
1712 MO_Nat_Ne -> condIntCode NE x y
1714 MO_NatS_Gt -> condIntCode GTT x y
1715 MO_NatS_Ge -> condIntCode GE x y
1716 MO_NatS_Lt -> condIntCode LTT x y
1717 MO_NatS_Le -> condIntCode LE x y
1719 MO_NatU_Gt -> condIntCode GU x y
1720 MO_NatU_Ge -> condIntCode GEU x y
1721 MO_NatU_Lt -> condIntCode LU x y
1722 MO_NatU_Le -> condIntCode LEU x y
1724 MO_Flt_Gt -> condFltCode GTT x y
1725 MO_Flt_Ge -> condFltCode GE x y
1726 MO_Flt_Eq -> condFltCode EQQ x y
1727 MO_Flt_Ne -> condFltCode NE x y
1728 MO_Flt_Lt -> condFltCode LTT x y
1729 MO_Flt_Le -> condFltCode LE x y
1731 MO_Dbl_Gt -> condFltCode GTT x y
1732 MO_Dbl_Ge -> condFltCode GE x y
1733 MO_Dbl_Eq -> condFltCode EQQ x y
1734 MO_Dbl_Ne -> condFltCode NE x y
1735 MO_Dbl_Lt -> condFltCode LTT x y
1736 MO_Dbl_Le -> condFltCode LE x y
1738 other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
1740 getCondCode other = pprPanic "getCondCode(2)(x86,sparc)" (pprStixExpr other)
1742 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1744 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1749 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1750 passed back up the tree.
1753 condIntCode, condFltCode :: Cond -> StixExpr -> StixExpr -> NatM CondCode
1755 #if alpha_TARGET_ARCH
1756 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1757 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1758 #endif {- alpha_TARGET_ARCH -}
1760 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1761 #if i386_TARGET_ARCH
1763 -- memory vs immediate
1764 condIntCode cond (StInd pk x) y
1765 | Just i <- maybeImm y
1766 = getAmode x `thenNat` \ amode ->
1768 code1 = amodeCode amode
1769 x__2 = amodeAddr amode
1770 sz = primRepToSize pk
1771 code__2 = code1 `snocOL`
1772 CMP sz (OpImm i) (OpAddr x__2)
1774 returnNat (CondCode False cond code__2)
1777 condIntCode cond x (StInt 0)
1778 = getRegister x `thenNat` \ register1 ->
1779 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1781 code1 = registerCode register1 tmp1
1782 src1 = registerName register1 tmp1
1783 code__2 = code1 `snocOL`
1784 TEST L (OpReg src1) (OpReg src1)
1786 returnNat (CondCode False cond code__2)
1788 -- anything vs immediate
1789 condIntCode cond x y
1790 | Just i <- maybeImm y
1791 = getRegister x `thenNat` \ register1 ->
1792 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1794 code1 = registerCode register1 tmp1
1795 src1 = registerName register1 tmp1
1796 code__2 = code1 `snocOL`
1797 CMP L (OpImm i) (OpReg src1)
1799 returnNat (CondCode False cond code__2)
1801 -- memory vs anything
1802 condIntCode cond (StInd pk x) y
1803 = getAmode x `thenNat` \ amode_x ->
1804 getRegister y `thenNat` \ reg_y ->
1805 getNewRegNCG IntRep `thenNat` \ tmp ->
1807 c_x = amodeCode amode_x
1808 am_x = amodeAddr amode_x
1809 c_y = registerCode reg_y tmp
1810 r_y = registerName reg_y tmp
1811 sz = primRepToSize pk
1813 -- optimisation: if there's no code for x, just an amode,
1814 -- use whatever reg y winds up in. Assumes that c_y doesn't
1815 -- clobber any regs in the amode am_x, which I'm not sure is
1816 -- justified. The otherwise clause makes the same assumption.
1817 code__2 | isNilOL c_x
1819 CMP sz (OpReg r_y) (OpAddr am_x)
1823 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1825 CMP sz (OpReg tmp) (OpAddr am_x)
1827 returnNat (CondCode False cond code__2)
1829 -- anything vs memory
1831 condIntCode cond y (StInd pk x)
1832 = getAmode x `thenNat` \ amode_x ->
1833 getRegister y `thenNat` \ reg_y ->
1834 getNewRegNCG IntRep `thenNat` \ tmp ->
1836 c_x = amodeCode amode_x
1837 am_x = amodeAddr amode_x
1838 c_y = registerCode reg_y tmp
1839 r_y = registerName reg_y tmp
1840 sz = primRepToSize pk
1841 -- same optimisation and nagging doubts as previous clause
1842 code__2 | isNilOL c_x
1844 CMP sz (OpAddr am_x) (OpReg r_y)
1848 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1850 CMP sz (OpAddr am_x) (OpReg tmp)
1852 returnNat (CondCode False cond code__2)
1854 -- anything vs anything
1855 condIntCode cond x y
1856 = getRegister x `thenNat` \ register1 ->
1857 getRegister y `thenNat` \ register2 ->
1858 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1859 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1861 code1 = registerCode register1 tmp1
1862 src1 = registerName register1 tmp1
1863 code2 = registerCode register2 tmp2
1864 src2 = registerName register2 tmp2
1865 code__2 = code1 `snocOL`
1866 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1868 CMP L (OpReg src2) (OpReg tmp1)
1870 returnNat (CondCode False cond code__2)
1873 condFltCode cond x y
1874 = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT]))
1875 getRegister x `thenNat` \ register1 ->
1876 getRegister y `thenNat` \ register2 ->
1877 getNewRegNCG (registerRep register1)
1879 getNewRegNCG (registerRep register2)
1881 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1883 code1 = registerCode register1 tmp1
1884 src1 = registerName register1 tmp1
1886 code2 = registerCode register2 tmp2
1887 src2 = registerName register2 tmp2
1889 code__2 | isAny register1
1890 = code1 `appOL` -- result in tmp1
1896 GMOV src1 tmp1 `appOL`
1900 -- The GCMP insn does the test and sets the zero flag if comparable
1901 -- and true. Hence we always supply EQQ as the condition to test.
1902 returnNat (CondCode True EQQ code__2)
1904 #endif {- i386_TARGET_ARCH -}
1906 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1908 #if sparc_TARGET_ARCH
1910 condIntCode cond x (StInt y)
1912 = getRegister x `thenNat` \ register ->
1913 getNewRegNCG IntRep `thenNat` \ tmp ->
1915 code = registerCode register tmp
1916 src1 = registerName register tmp
1917 src2 = ImmInt (fromInteger y)
1918 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1920 returnNat (CondCode False cond code__2)
1922 condIntCode cond x y
1923 = getRegister x `thenNat` \ register1 ->
1924 getRegister y `thenNat` \ register2 ->
1925 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1926 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1928 code1 = registerCode register1 tmp1
1929 src1 = registerName register1 tmp1
1930 code2 = registerCode register2 tmp2
1931 src2 = registerName register2 tmp2
1932 code__2 = code1 `appOL` code2 `snocOL`
1933 SUB False True src1 (RIReg src2) g0
1935 returnNat (CondCode False cond code__2)
1938 condFltCode cond x y
1939 = getRegister x `thenNat` \ register1 ->
1940 getRegister y `thenNat` \ register2 ->
1941 getNewRegNCG (registerRep register1)
1943 getNewRegNCG (registerRep register2)
1945 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1947 promote x = FxTOy F DF x tmp
1949 pk1 = registerRep register1
1950 code1 = registerCode register1 tmp1
1951 src1 = registerName register1 tmp1
1953 pk2 = registerRep register2
1954 code2 = registerCode register2 tmp2
1955 src2 = registerName register2 tmp2
1959 code1 `appOL` code2 `snocOL`
1960 FCMP True (primRepToSize pk1) src1 src2
1961 else if pk1 == FloatRep then
1962 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1963 FCMP True DF tmp src2
1965 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1966 FCMP True DF src1 tmp
1968 returnNat (CondCode True cond code__2)
1970 #endif {- sparc_TARGET_ARCH -}
1972 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1975 %************************************************************************
1977 \subsection{Generating assignments}
1979 %************************************************************************
1981 Assignments are really at the heart of the whole code generation
1982 business. Almost all top-level nodes of any real importance are
1983 assignments, which correspond to loads, stores, or register transfers.
1984 If we're really lucky, some of the register transfers will go away,
1985 because we can use the destination register to complete the code
1986 generation for the right hand side. This only fails when the right
1987 hand side is forced into a fixed register (e.g. the result of a call).
1990 assignMem_IntCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
1991 assignReg_IntCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
1993 assignMem_FltCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
1994 assignReg_FltCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
1996 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1998 #if alpha_TARGET_ARCH
2000 assignIntCode pk (StInd _ dst) src
2001 = getNewRegNCG IntRep `thenNat` \ tmp ->
2002 getAmode dst `thenNat` \ amode ->
2003 getRegister src `thenNat` \ register ->
2005 code1 = amodeCode amode []
2006 dst__2 = amodeAddr amode
2007 code2 = registerCode register tmp []
2008 src__2 = registerName register tmp
2009 sz = primRepToSize pk
2010 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2014 assignIntCode pk dst src
2015 = getRegister dst `thenNat` \ register1 ->
2016 getRegister src `thenNat` \ register2 ->
2018 dst__2 = registerName register1 zeroh
2019 code = registerCode register2 dst__2
2020 src__2 = registerName register2 dst__2
2021 code__2 = if isFixed register2
2022 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
2027 #endif {- alpha_TARGET_ARCH -}
2029 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2031 #if i386_TARGET_ARCH
2033 -- non-FP assignment to memory
2034 assignMem_IntCode pk addr src
2035 = getAmode addr `thenNat` \ amode ->
2036 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
2037 getNewRegNCG PtrRep `thenNat` \ tmp ->
2039 -- In general, if the address computation for dst may require
2040 -- some insns preceding the addressing mode itself. So there's
2041 -- no guarantee that the code for dst and the code for src won't
2042 -- write the same register. This means either the address or
2043 -- the value needs to be copied into a temporary. We detect the
2044 -- common case where the amode has no code, and elide the copy.
2045 codea = amodeCode amode
2046 dst__a = amodeAddr amode
2048 code | isNilOL codea
2050 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
2053 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
2055 MOV (primRepToSize pk) opsrc
2056 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
2062 -> NatM (InstrBlock,Operand) -- code, operator
2065 | Just x <- maybeImm op
2066 = returnNat (nilOL, OpImm x)
2069 = getRegister op `thenNat` \ register ->
2070 getNewRegNCG (registerRep register)
2072 let code = registerCode register tmp
2073 reg = registerName register tmp
2075 returnNat (code, OpReg reg)
2077 -- Assign; dst is a reg, rhs is mem
2078 assignReg_IntCode pk reg (StInd pks src)
2079 = getNewRegNCG PtrRep `thenNat` \ tmp ->
2080 getAmode src `thenNat` \ amode ->
2081 getRegisterReg reg `thenNat` \ reg_dst ->
2083 c_addr = amodeCode amode
2084 am_addr = amodeAddr amode
2085 r_dst = registerName reg_dst tmp
2086 szs = primRepToSize pks
2095 code = c_addr `snocOL`
2096 opc (OpAddr am_addr) (OpReg r_dst)
2100 -- dst is a reg, but src could be anything
2101 assignReg_IntCode pk reg src
2102 = getRegisterReg reg `thenNat` \ registerd ->
2103 getRegister src `thenNat` \ registers ->
2104 getNewRegNCG IntRep `thenNat` \ tmp ->
2106 r_dst = registerName registerd tmp
2107 r_src = registerName registers r_dst
2108 c_src = registerCode registers r_dst
2110 code = c_src `snocOL`
2111 MOV L (OpReg r_src) (OpReg r_dst)
2115 #endif {- i386_TARGET_ARCH -}
2117 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2119 #if sparc_TARGET_ARCH
2121 assignMem_IntCode pk addr src
2122 = getNewRegNCG IntRep `thenNat` \ tmp ->
2123 getAmode addr `thenNat` \ amode ->
2124 getRegister src `thenNat` \ register ->
2126 code1 = amodeCode amode
2127 dst__2 = amodeAddr amode
2128 code2 = registerCode register tmp
2129 src__2 = registerName register tmp
2130 sz = primRepToSize pk
2131 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
2135 assignReg_IntCode pk reg src
2136 = getRegister src `thenNat` \ register2 ->
2137 getRegisterReg reg `thenNat` \ register1 ->
2139 dst__2 = registerName register1 g0
2140 code = registerCode register2 dst__2
2141 src__2 = registerName register2 dst__2
2142 code__2 = if isFixed register2
2143 then code `snocOL` OR False g0 (RIReg src__2) dst__2
2148 #endif {- sparc_TARGET_ARCH -}
2150 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2153 % --------------------------------
2154 Floating-point assignments:
2155 % --------------------------------
2158 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2159 #if alpha_TARGET_ARCH
2161 assignFltCode pk (StInd _ dst) src
2162 = getNewRegNCG pk `thenNat` \ tmp ->
2163 getAmode dst `thenNat` \ amode ->
2164 getRegister src `thenNat` \ register ->
2166 code1 = amodeCode amode []
2167 dst__2 = amodeAddr amode
2168 code2 = registerCode register tmp []
2169 src__2 = registerName register tmp
2170 sz = primRepToSize pk
2171 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2175 assignFltCode pk dst src
2176 = getRegister dst `thenNat` \ register1 ->
2177 getRegister src `thenNat` \ register2 ->
2179 dst__2 = registerName register1 zeroh
2180 code = registerCode register2 dst__2
2181 src__2 = registerName register2 dst__2
2182 code__2 = if isFixed register2
2183 then code . mkSeqInstr (FMOV src__2 dst__2)
2188 #endif {- alpha_TARGET_ARCH -}
2190 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2192 #if i386_TARGET_ARCH
2194 -- Floating point assignment to memory
2195 assignMem_FltCode pk addr src
2196 = getRegister src `thenNat` \ reg_src ->
2197 getRegister addr `thenNat` \ reg_addr ->
2198 getNewRegNCG pk `thenNat` \ tmp_src ->
2199 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
2200 let r_src = registerName reg_src tmp_src
2201 c_src = registerCode reg_src tmp_src
2202 r_addr = registerName reg_addr tmp_addr
2203 c_addr = registerCode reg_addr tmp_addr
2204 sz = primRepToSize pk
2206 code = c_src `appOL`
2207 -- no need to preserve r_src across the addr computation,
2208 -- since r_src must be a float reg
2209 -- whilst r_addr is an int reg
2212 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
2216 -- Floating point assignment to a register/temporary
2217 assignReg_FltCode pk reg src
2218 = getRegisterReg reg `thenNat` \ reg_dst ->
2219 getRegister src `thenNat` \ reg_src ->
2220 getNewRegNCG pk `thenNat` \ tmp ->
2222 r_dst = registerName reg_dst tmp
2223 r_src = registerName reg_src r_dst
2224 c_src = registerCode reg_src r_dst
2226 code = if isFixed reg_src
2227 then c_src `snocOL` GMOV r_src r_dst
2233 #endif {- i386_TARGET_ARCH -}
2235 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2237 #if sparc_TARGET_ARCH
2239 -- Floating point assignment to memory
2240 assignMem_FltCode pk addr src
2241 = getNewRegNCG pk `thenNat` \ tmp1 ->
2242 getAmode addr `thenNat` \ amode ->
2243 getRegister src `thenNat` \ register ->
2245 sz = primRepToSize pk
2246 dst__2 = amodeAddr amode
2248 code1 = amodeCode amode
2249 code2 = registerCode register tmp1
2251 src__2 = registerName register tmp1
2252 pk__2 = registerRep register
2253 sz__2 = primRepToSize pk__2
2255 code__2 = code1 `appOL` code2 `appOL`
2257 then unitOL (ST sz src__2 dst__2)
2258 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
2262 -- Floating point assignment to a register/temporary
2263 -- Why is this so bizarrely ugly?
2264 assignReg_FltCode pk reg src
2265 = getRegisterReg reg `thenNat` \ register1 ->
2266 getRegister src `thenNat` \ register2 ->
2268 pk__2 = registerRep register2
2269 sz__2 = primRepToSize pk__2
2271 getNewRegNCG pk__2 `thenNat` \ tmp ->
2273 sz = primRepToSize pk
2274 dst__2 = registerName register1 g0 -- must be Fixed
2275 reg__2 = if pk /= pk__2 then tmp else dst__2
2276 code = registerCode register2 reg__2
2277 src__2 = registerName register2 reg__2
2280 code `snocOL` FxTOy sz__2 sz src__2 dst__2
2281 else if isFixed register2 then
2282 code `snocOL` FMOV sz src__2 dst__2
2288 #endif {- sparc_TARGET_ARCH -}
2290 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2293 %************************************************************************
2295 \subsection{Generating an unconditional branch}
2297 %************************************************************************
2299 We accept two types of targets: an immediate CLabel or a tree that
2300 gets evaluated into a register. Any CLabels which are AsmTemporaries
2301 are assumed to be in the local block of code, close enough for a
2302 branch instruction. Other CLabels are assumed to be far away.
2304 (If applicable) Do not fill the delay slots here; you will confuse the
2308 genJump :: DestInfo -> StixExpr{-the branch target-} -> NatM InstrBlock
2310 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2312 #if alpha_TARGET_ARCH
2314 genJump (StCLbl lbl)
2315 | isAsmTemp lbl = returnInstr (BR target)
2316 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2318 target = ImmCLbl lbl
2321 = getRegister tree `thenNat` \ register ->
2322 getNewRegNCG PtrRep `thenNat` \ tmp ->
2324 dst = registerName register pv
2325 code = registerCode register pv
2326 target = registerName register pv
2328 if isFixed register then
2329 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2331 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2333 #endif {- alpha_TARGET_ARCH -}
2335 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2337 #if i386_TARGET_ARCH
2339 genJump dsts (StInd pk mem)
2340 = getAmode mem `thenNat` \ amode ->
2342 code = amodeCode amode
2343 target = amodeAddr amode
2345 returnNat (code `snocOL` JMP dsts (OpAddr target))
2349 = returnNat (unitOL (JMP dsts (OpImm target)))
2352 = getRegister tree `thenNat` \ register ->
2353 getNewRegNCG PtrRep `thenNat` \ tmp ->
2355 code = registerCode register tmp
2356 target = registerName register tmp
2358 returnNat (code `snocOL` JMP dsts (OpReg target))
2361 target = case imm of Just x -> x
2363 #endif {- i386_TARGET_ARCH -}
2365 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2367 #if sparc_TARGET_ARCH
2369 genJump dsts (StCLbl lbl)
2370 | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
2371 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2372 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
2374 target = ImmCLbl lbl
2377 = getRegister tree `thenNat` \ register ->
2378 getNewRegNCG PtrRep `thenNat` \ tmp ->
2380 code = registerCode register tmp
2381 target = registerName register tmp
2383 returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
2385 #endif {- sparc_TARGET_ARCH -}
2387 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2390 %************************************************************************
2392 \subsection{Conditional jumps}
2394 %************************************************************************
2396 Conditional jumps are always to local labels, so we can use branch
2397 instructions. We peek at the arguments to decide what kind of
2400 ALPHA: For comparisons with 0, we're laughing, because we can just do
2401 the desired conditional branch.
2403 I386: First, we have to ensure that the condition
2404 codes are set according to the supplied comparison operation.
2406 SPARC: First, we have to ensure that the condition codes are set
2407 according to the supplied comparison operation. We generate slightly
2408 different code for floating point comparisons, because a floating
2409 point operation cannot directly precede a @BF@. We assume the worst
2410 and fill that slot with a @NOP@.
2412 SPARC: Do not fill the delay slots here; you will confuse the register
2417 :: CLabel -- the branch target
2418 -> StixExpr -- the condition on which to branch
2421 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2423 #if alpha_TARGET_ARCH
2425 genCondJump lbl (StPrim op [x, StInt 0])
2426 = getRegister x `thenNat` \ register ->
2427 getNewRegNCG (registerRep register)
2430 code = registerCode register tmp
2431 value = registerName register tmp
2432 pk = registerRep register
2433 target = ImmCLbl lbl
2435 returnSeq code [BI (cmpOp op) value target]
2437 cmpOp CharGtOp = GTT
2439 cmpOp CharEqOp = EQQ
2441 cmpOp CharLtOp = LTT
2450 cmpOp WordGeOp = ALWAYS
2451 cmpOp WordEqOp = EQQ
2453 cmpOp WordLtOp = NEVER
2454 cmpOp WordLeOp = EQQ
2456 cmpOp AddrGeOp = ALWAYS
2457 cmpOp AddrEqOp = EQQ
2459 cmpOp AddrLtOp = NEVER
2460 cmpOp AddrLeOp = EQQ
2462 genCondJump lbl (StPrim op [x, StDouble 0.0])
2463 = getRegister x `thenNat` \ register ->
2464 getNewRegNCG (registerRep register)
2467 code = registerCode register tmp
2468 value = registerName register tmp
2469 pk = registerRep register
2470 target = ImmCLbl lbl
2472 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2474 cmpOp FloatGtOp = GTT
2475 cmpOp FloatGeOp = GE
2476 cmpOp FloatEqOp = EQQ
2477 cmpOp FloatNeOp = NE
2478 cmpOp FloatLtOp = LTT
2479 cmpOp FloatLeOp = LE
2480 cmpOp DoubleGtOp = GTT
2481 cmpOp DoubleGeOp = GE
2482 cmpOp DoubleEqOp = EQQ
2483 cmpOp DoubleNeOp = NE
2484 cmpOp DoubleLtOp = LTT
2485 cmpOp DoubleLeOp = LE
2487 genCondJump lbl (StPrim op [x, y])
2489 = trivialFCode pr instr x y `thenNat` \ register ->
2490 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2492 code = registerCode register tmp
2493 result = registerName register tmp
2494 target = ImmCLbl lbl
2496 returnNat (code . mkSeqInstr (BF cond result target))
2498 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2500 fltCmpOp op = case op of
2514 (instr, cond) = case op of
2515 FloatGtOp -> (FCMP TF LE, EQQ)
2516 FloatGeOp -> (FCMP TF LTT, EQQ)
2517 FloatEqOp -> (FCMP TF EQQ, NE)
2518 FloatNeOp -> (FCMP TF EQQ, EQQ)
2519 FloatLtOp -> (FCMP TF LTT, NE)
2520 FloatLeOp -> (FCMP TF LE, NE)
2521 DoubleGtOp -> (FCMP TF LE, EQQ)
2522 DoubleGeOp -> (FCMP TF LTT, EQQ)
2523 DoubleEqOp -> (FCMP TF EQQ, NE)
2524 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2525 DoubleLtOp -> (FCMP TF LTT, NE)
2526 DoubleLeOp -> (FCMP TF LE, NE)
2528 genCondJump lbl (StPrim op [x, y])
2529 = trivialCode instr x y `thenNat` \ register ->
2530 getNewRegNCG IntRep `thenNat` \ tmp ->
2532 code = registerCode register tmp
2533 result = registerName register tmp
2534 target = ImmCLbl lbl
2536 returnNat (code . mkSeqInstr (BI cond result target))
2538 (instr, cond) = case op of
2539 CharGtOp -> (CMP LE, EQQ)
2540 CharGeOp -> (CMP LTT, EQQ)
2541 CharEqOp -> (CMP EQQ, NE)
2542 CharNeOp -> (CMP EQQ, EQQ)
2543 CharLtOp -> (CMP LTT, NE)
2544 CharLeOp -> (CMP LE, NE)
2545 IntGtOp -> (CMP LE, EQQ)
2546 IntGeOp -> (CMP LTT, EQQ)
2547 IntEqOp -> (CMP EQQ, NE)
2548 IntNeOp -> (CMP EQQ, EQQ)
2549 IntLtOp -> (CMP LTT, NE)
2550 IntLeOp -> (CMP LE, NE)
2551 WordGtOp -> (CMP ULE, EQQ)
2552 WordGeOp -> (CMP ULT, EQQ)
2553 WordEqOp -> (CMP EQQ, NE)
2554 WordNeOp -> (CMP EQQ, EQQ)
2555 WordLtOp -> (CMP ULT, NE)
2556 WordLeOp -> (CMP ULE, NE)
2557 AddrGtOp -> (CMP ULE, EQQ)
2558 AddrGeOp -> (CMP ULT, EQQ)
2559 AddrEqOp -> (CMP EQQ, NE)
2560 AddrNeOp -> (CMP EQQ, EQQ)
2561 AddrLtOp -> (CMP ULT, NE)
2562 AddrLeOp -> (CMP ULE, NE)
2564 #endif {- alpha_TARGET_ARCH -}
2566 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2568 #if i386_TARGET_ARCH
2570 genCondJump lbl bool
2571 = getCondCode bool `thenNat` \ condition ->
2573 code = condCode condition
2574 cond = condName condition
2576 returnNat (code `snocOL` JXX cond lbl)
2578 #endif {- i386_TARGET_ARCH -}
2580 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2582 #if sparc_TARGET_ARCH
2584 genCondJump lbl bool
2585 = getCondCode bool `thenNat` \ condition ->
2587 code = condCode condition
2588 cond = condName condition
2589 target = ImmCLbl lbl
2594 if condFloat condition
2595 then [NOP, BF cond False target, NOP]
2596 else [BI cond False target, NOP]
2600 #endif {- sparc_TARGET_ARCH -}
2602 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2605 %************************************************************************
2607 \subsection{Generating C calls}
2609 %************************************************************************
2611 Now the biggest nightmare---calls. Most of the nastiness is buried in
2612 @get_arg@, which moves the arguments to the correct registers/stack
2613 locations. Apart from that, the code is easy.
2615 (If applicable) Do not fill the delay slots here; you will confuse the
2620 :: FAST_STRING -- function to call
2622 -> PrimRep -- type of the result
2623 -> [StixExpr] -- arguments (of mixed type)
2626 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2628 #if alpha_TARGET_ARCH
2630 genCCall fn cconv kind args
2631 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2632 `thenNat` \ ((unused,_), argCode) ->
2634 nRegs = length allArgRegs - length unused
2635 code = asmSeqThen (map ($ []) argCode)
2638 LDA pv (AddrImm (ImmLab (ptext fn))),
2639 JSR ra (AddrReg pv) nRegs,
2640 LDGP gp (AddrReg ra)]
2642 ------------------------
2643 {- Try to get a value into a specific register (or registers) for
2644 a call. The first 6 arguments go into the appropriate
2645 argument register (separate registers for integer and floating
2646 point arguments, but used in lock-step), and the remaining
2647 arguments are dumped to the stack, beginning at 0(sp). Our
2648 first argument is a pair of the list of remaining argument
2649 registers to be assigned for this call and the next stack
2650 offset to use for overflowing arguments. This way,
2651 @get_Arg@ can be applied to all of a call's arguments using
2655 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2656 -> StixTree -- Current argument
2657 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2659 -- We have to use up all of our argument registers first...
2661 get_arg ((iDst,fDst):dsts, offset) arg
2662 = getRegister arg `thenNat` \ register ->
2664 reg = if isFloatingRep pk then fDst else iDst
2665 code = registerCode register reg
2666 src = registerName register reg
2667 pk = registerRep register
2670 if isFloatingRep pk then
2671 ((dsts, offset), if isFixed register then
2672 code . mkSeqInstr (FMOV src fDst)
2675 ((dsts, offset), if isFixed register then
2676 code . mkSeqInstr (OR src (RIReg src) iDst)
2679 -- Once we have run out of argument registers, we move to the
2682 get_arg ([], offset) arg
2683 = getRegister arg `thenNat` \ register ->
2684 getNewRegNCG (registerRep register)
2687 code = registerCode register tmp
2688 src = registerName register tmp
2689 pk = registerRep register
2690 sz = primRepToSize pk
2692 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2694 #endif {- alpha_TARGET_ARCH -}
2696 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2698 #if i386_TARGET_ARCH
2700 genCCall fn cconv ret_rep [StInt i]
2701 | fn == SLIT ("PerformGC_wrapper")
2703 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2704 CALL (ImmLit (ptext (if underscorePrefix
2705 then (SLIT ("_PerformGC_wrapper"))
2706 else (SLIT ("PerformGC_wrapper")))))
2712 genCCall fn cconv ret_rep args
2714 (reverse args) `thenNat` \ sizes_n_codes ->
2715 getDeltaNat `thenNat` \ delta ->
2716 let (sizes, codes) = unzip sizes_n_codes
2717 tot_arg_size = sum sizes
2718 code2 = concatOL codes
2720 [CALL (fn__2 tot_arg_size)]
2722 -- Deallocate parameters after call for ccall;
2723 -- but not for stdcall (callee does it)
2724 (if cconv == StdCallConv then [] else
2725 [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2728 [DELTA (delta + tot_arg_size)]
2731 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2732 returnNat (code2 `appOL` call)
2735 -- function names that begin with '.' are assumed to be special
2736 -- internally generated names like '.mul,' which don't get an
2737 -- underscore prefix
2738 -- ToDo:needed (WDP 96/03) ???
2742 = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
2743 | otherwise -- General case
2744 = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
2746 stdcallsize tot_arg_size
2747 | cconv == StdCallConv = '@':show tot_arg_size
2755 push_arg :: StixExpr{-current argument-}
2756 -> NatM (Int, InstrBlock) -- argsz, code
2759 | is64BitRep arg_rep
2760 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2761 getDeltaNat `thenNat` \ delta ->
2762 setDeltaNat (delta - 8) `thenNat` \ _ ->
2763 let r_lo = VirtualRegI vr_lo
2764 r_hi = getHiVRegFromLo r_lo
2767 toOL [PUSH L (OpReg r_hi), DELTA (delta - 4),
2768 PUSH L (OpReg r_lo), DELTA (delta - 8)]
2771 = get_op arg `thenNat` \ (code, reg, sz) ->
2772 getDeltaNat `thenNat` \ delta ->
2773 arg_size sz `bind` \ size ->
2774 setDeltaNat (delta-size) `thenNat` \ _ ->
2775 if (case sz of DF -> True; F -> True; _ -> False)
2776 then returnNat (size,
2778 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2780 GST sz reg (AddrBaseIndex (Just esp)
2784 else returnNat (size,
2786 PUSH L (OpReg reg) `snocOL`
2790 arg_rep = repOfStixExpr arg
2795 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2798 = getRegister op `thenNat` \ register ->
2799 getNewRegNCG (registerRep register)
2802 code = registerCode register tmp
2803 reg = registerName register tmp
2804 pk = registerRep register
2805 sz = primRepToSize pk
2807 returnNat (code, reg, sz)
2809 #endif {- i386_TARGET_ARCH -}
2811 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2813 #if sparc_TARGET_ARCH
2815 The SPARC calling convention is an absolute
2816 nightmare. The first 6x32 bits of arguments are mapped into
2817 %o0 through %o5, and the remaining arguments are dumped to the
2818 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
2820 If we have to put args on the stack, move %o6==%sp down by
2821 the number of words to go on the stack, to ensure there's enough space.
2823 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
2824 16 words above the stack pointer is a word for the address of
2825 a structure return value. I use this as a temporary location
2826 for moving values from float to int regs. Certainly it isn't
2827 safe to put anything in the 16 words starting at %sp, since
2828 this area can get trashed at any time due to window overflows
2829 caused by signal handlers.
2831 A final complication (if the above isn't enough) is that
2832 we can't blithely calculate the arguments one by one into
2833 %o0 .. %o5. Consider the following nested calls:
2837 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
2838 the inner call will itself use %o0, which trashes the value put there
2839 in preparation for the outer call. Upshot: we need to calculate the
2840 args into temporary regs, and move those to arg regs or onto the
2841 stack only immediately prior to the call proper. Sigh.
2844 genCCall fn cconv kind args
2845 = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
2846 let (argcodes, vregss) = unzip argcode_and_vregs
2847 argcode = concatOL argcodes
2848 vregs = concat vregss
2849 n_argRegs = length allArgRegs
2850 n_argRegs_used = min (length vregs) n_argRegs
2851 (move_sp_down, move_sp_up)
2852 = let nn = length vregs - n_argRegs
2853 + 1 -- (for the road)
2856 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
2858 = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
2860 = unitOL (CALL fn__2 n_argRegs_used False)
2862 returnNat (argcode `appOL`
2863 move_sp_down `appOL`
2864 transfer_code `appOL`
2869 -- function names that begin with '.' are assumed to be special
2870 -- internally generated names like '.mul,' which don't get an
2871 -- underscore prefix
2872 -- ToDo:needed (WDP 96/03) ???
2873 fn__2 = case (_HEAD_ fn) of
2874 '.' -> ImmLit (ptext fn)
2875 _ -> ImmLab False (ptext fn)
2877 -- move args from the integer vregs into which they have been
2878 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
2879 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
2881 move_final [] _ offset -- all args done
2884 move_final (v:vs) [] offset -- out of aregs; move to stack
2885 = ST W v (spRel offset)
2886 : move_final vs [] (offset+1)
2888 move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
2889 = OR False g0 (RIReg v) a
2890 : move_final vs az offset
2892 -- generate code to calculate an argument, and move it into one
2893 -- or two integer vregs.
2894 arg_to_int_vregs :: StixExpr -> NatM (OrdList Instr, [Reg])
2895 arg_to_int_vregs arg
2896 | is64BitRep (repOfStixExpr arg)
2897 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2898 let r_lo = VirtualRegI vr_lo
2899 r_hi = getHiVRegFromLo r_lo
2900 in returnNat (code, [r_hi, r_lo])
2902 = getRegister arg `thenNat` \ register ->
2903 getNewRegNCG (registerRep register) `thenNat` \ tmp ->
2904 let code = registerCode register tmp
2905 src = registerName register tmp
2906 pk = registerRep register
2908 -- the value is in src. Get it into 1 or 2 int vregs.
2911 getNewRegNCG WordRep `thenNat` \ v1 ->
2912 getNewRegNCG WordRep `thenNat` \ v2 ->
2915 FMOV DF src f0 `snocOL`
2916 ST F f0 (spRel 16) `snocOL`
2917 LD W (spRel 16) v1 `snocOL`
2918 ST F (fPair f0) (spRel 16) `snocOL`
2924 getNewRegNCG WordRep `thenNat` \ v1 ->
2927 ST F src (spRel 16) `snocOL`
2933 getNewRegNCG WordRep `thenNat` \ v1 ->
2935 code `snocOL` OR False g0 (RIReg src) v1
2939 #endif {- sparc_TARGET_ARCH -}
2941 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2944 %************************************************************************
2946 \subsection{Support bits}
2948 %************************************************************************
2950 %************************************************************************
2952 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2954 %************************************************************************
2956 Turn those condition codes into integers now (when they appear on
2957 the right hand side of an assignment).
2959 (If applicable) Do not fill the delay slots here; you will confuse the
2963 condIntReg, condFltReg :: Cond -> StixExpr -> StixExpr -> NatM Register
2965 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2967 #if alpha_TARGET_ARCH
2968 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2969 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2970 #endif {- alpha_TARGET_ARCH -}
2972 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2974 #if i386_TARGET_ARCH
2977 = condIntCode cond x y `thenNat` \ condition ->
2978 getNewRegNCG IntRep `thenNat` \ tmp ->
2980 code = condCode condition
2981 cond = condName condition
2982 code__2 dst = code `appOL` toOL [
2983 SETCC cond (OpReg tmp),
2984 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2985 MOV L (OpReg tmp) (OpReg dst)]
2987 returnNat (Any IntRep code__2)
2990 = getNatLabelNCG `thenNat` \ lbl1 ->
2991 getNatLabelNCG `thenNat` \ lbl2 ->
2992 condFltCode cond x y `thenNat` \ condition ->
2994 code = condCode condition
2995 cond = condName condition
2996 code__2 dst = code `appOL` toOL [
2998 MOV L (OpImm (ImmInt 0)) (OpReg dst),
3001 MOV L (OpImm (ImmInt 1)) (OpReg dst),
3004 returnNat (Any IntRep code__2)
3006 #endif {- i386_TARGET_ARCH -}
3008 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3010 #if sparc_TARGET_ARCH
3012 condIntReg EQQ x (StInt 0)
3013 = getRegister x `thenNat` \ register ->
3014 getNewRegNCG IntRep `thenNat` \ tmp ->
3016 code = registerCode register tmp
3017 src = registerName register tmp
3018 code__2 dst = code `appOL` toOL [
3019 SUB False True g0 (RIReg src) g0,
3020 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3022 returnNat (Any IntRep code__2)
3025 = getRegister x `thenNat` \ register1 ->
3026 getRegister y `thenNat` \ register2 ->
3027 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3028 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3030 code1 = registerCode register1 tmp1
3031 src1 = registerName register1 tmp1
3032 code2 = registerCode register2 tmp2
3033 src2 = registerName register2 tmp2
3034 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3035 XOR False src1 (RIReg src2) dst,
3036 SUB False True g0 (RIReg dst) g0,
3037 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3039 returnNat (Any IntRep code__2)
3041 condIntReg NE x (StInt 0)
3042 = getRegister x `thenNat` \ register ->
3043 getNewRegNCG IntRep `thenNat` \ tmp ->
3045 code = registerCode register tmp
3046 src = registerName register tmp
3047 code__2 dst = code `appOL` toOL [
3048 SUB False True g0 (RIReg src) g0,
3049 ADD True False g0 (RIImm (ImmInt 0)) dst]
3051 returnNat (Any IntRep code__2)
3054 = getRegister x `thenNat` \ register1 ->
3055 getRegister y `thenNat` \ register2 ->
3056 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3057 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3059 code1 = registerCode register1 tmp1
3060 src1 = registerName register1 tmp1
3061 code2 = registerCode register2 tmp2
3062 src2 = registerName register2 tmp2
3063 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3064 XOR False src1 (RIReg src2) dst,
3065 SUB False True g0 (RIReg dst) g0,
3066 ADD True False g0 (RIImm (ImmInt 0)) dst]
3068 returnNat (Any IntRep code__2)
3071 = getNatLabelNCG `thenNat` \ lbl1 ->
3072 getNatLabelNCG `thenNat` \ lbl2 ->
3073 condIntCode cond x y `thenNat` \ condition ->
3075 code = condCode condition
3076 cond = condName condition
3077 code__2 dst = code `appOL` toOL [
3078 BI cond False (ImmCLbl lbl1), NOP,
3079 OR False g0 (RIImm (ImmInt 0)) dst,
3080 BI ALWAYS False (ImmCLbl lbl2), NOP,
3082 OR False g0 (RIImm (ImmInt 1)) dst,
3085 returnNat (Any IntRep code__2)
3088 = getNatLabelNCG `thenNat` \ lbl1 ->
3089 getNatLabelNCG `thenNat` \ lbl2 ->
3090 condFltCode cond x y `thenNat` \ condition ->
3092 code = condCode condition
3093 cond = condName condition
3094 code__2 dst = code `appOL` toOL [
3096 BF cond False (ImmCLbl lbl1), NOP,
3097 OR False g0 (RIImm (ImmInt 0)) dst,
3098 BI ALWAYS False (ImmCLbl lbl2), NOP,
3100 OR False g0 (RIImm (ImmInt 1)) dst,
3103 returnNat (Any IntRep code__2)
3105 #endif {- sparc_TARGET_ARCH -}
3107 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3110 %************************************************************************
3112 \subsubsection{@trivial*Code@: deal with trivial instructions}
3114 %************************************************************************
3116 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
3117 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
3118 for constants on the right hand side, because that's where the generic
3119 optimizer will have put them.
3121 Similarly, for unary instructions, we don't have to worry about
3122 matching an StInt as the argument, because genericOpt will already
3123 have handled the constant-folding.
3127 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
3128 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
3129 -> Maybe (Operand -> Operand -> Instr)
3130 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
3132 -> StixExpr -> StixExpr -- the two arguments
3137 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
3138 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
3139 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
3141 -> StixExpr -> StixExpr -- the two arguments
3145 :: IF_ARCH_alpha((RI -> Reg -> Instr)
3146 ,IF_ARCH_i386 ((Operand -> Instr)
3147 ,IF_ARCH_sparc((RI -> Reg -> Instr)
3149 -> StixExpr -- the one argument
3154 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
3155 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
3156 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
3158 -> StixExpr -- the one argument
3161 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3163 #if alpha_TARGET_ARCH
3165 trivialCode instr x (StInt y)
3167 = getRegister x `thenNat` \ register ->
3168 getNewRegNCG IntRep `thenNat` \ tmp ->
3170 code = registerCode register tmp
3171 src1 = registerName register tmp
3172 src2 = ImmInt (fromInteger y)
3173 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
3175 returnNat (Any IntRep code__2)
3177 trivialCode instr x y
3178 = getRegister x `thenNat` \ register1 ->
3179 getRegister y `thenNat` \ register2 ->
3180 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3181 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3183 code1 = registerCode register1 tmp1 []
3184 src1 = registerName register1 tmp1
3185 code2 = registerCode register2 tmp2 []
3186 src2 = registerName register2 tmp2
3187 code__2 dst = asmSeqThen [code1, code2] .
3188 mkSeqInstr (instr src1 (RIReg src2) dst)
3190 returnNat (Any IntRep code__2)
3193 trivialUCode instr x
3194 = getRegister x `thenNat` \ register ->
3195 getNewRegNCG IntRep `thenNat` \ tmp ->
3197 code = registerCode register tmp
3198 src = registerName register tmp
3199 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3201 returnNat (Any IntRep code__2)
3204 trivialFCode _ instr x y
3205 = getRegister x `thenNat` \ register1 ->
3206 getRegister y `thenNat` \ register2 ->
3207 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3208 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3210 code1 = registerCode register1 tmp1
3211 src1 = registerName register1 tmp1
3213 code2 = registerCode register2 tmp2
3214 src2 = registerName register2 tmp2
3216 code__2 dst = asmSeqThen [code1 [], code2 []] .
3217 mkSeqInstr (instr src1 src2 dst)
3219 returnNat (Any DoubleRep code__2)
3221 trivialUFCode _ instr x
3222 = getRegister x `thenNat` \ register ->
3223 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3225 code = registerCode register tmp
3226 src = registerName register tmp
3227 code__2 dst = code . mkSeqInstr (instr src dst)
3229 returnNat (Any DoubleRep code__2)
3231 #endif {- alpha_TARGET_ARCH -}
3233 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3235 #if i386_TARGET_ARCH
3237 The Rules of the Game are:
3239 * You cannot assume anything about the destination register dst;
3240 it may be anything, including a fixed reg.
3242 * You may compute an operand into a fixed reg, but you may not
3243 subsequently change the contents of that fixed reg. If you
3244 want to do so, first copy the value either to a temporary
3245 or into dst. You are free to modify dst even if it happens
3246 to be a fixed reg -- that's not your problem.
3248 * You cannot assume that a fixed reg will stay live over an
3249 arbitrary computation. The same applies to the dst reg.
3251 * Temporary regs obtained from getNewRegNCG are distinct from
3252 each other and from all other regs, and stay live over
3253 arbitrary computations.
3257 trivialCode instr maybe_revinstr a b
3260 = getRegister a `thenNat` \ rega ->
3263 then registerCode rega dst `bind` \ code_a ->
3265 instr (OpImm imm_b) (OpReg dst)
3266 else registerCodeF rega `bind` \ code_a ->
3267 registerNameF rega `bind` \ r_a ->
3269 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3270 instr (OpImm imm_b) (OpReg dst)
3272 returnNat (Any IntRep mkcode)
3275 = getRegister b `thenNat` \ regb ->
3276 getNewRegNCG IntRep `thenNat` \ tmp ->
3277 let revinstr_avail = maybeToBool maybe_revinstr
3278 revinstr = case maybe_revinstr of Just ri -> ri
3282 then registerCode regb dst `bind` \ code_b ->
3284 revinstr (OpImm imm_a) (OpReg dst)
3285 else registerCodeF regb `bind` \ code_b ->
3286 registerNameF regb `bind` \ r_b ->
3288 MOV L (OpReg r_b) (OpReg dst) `snocOL`
3289 revinstr (OpImm imm_a) (OpReg dst)
3293 then registerCode regb tmp `bind` \ code_b ->
3295 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3296 instr (OpReg tmp) (OpReg dst)
3297 else registerCodeF regb `bind` \ code_b ->
3298 registerNameF regb `bind` \ r_b ->
3300 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
3301 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3302 instr (OpReg tmp) (OpReg dst)
3304 returnNat (Any IntRep mkcode)
3307 = getRegister a `thenNat` \ rega ->
3308 getRegister b `thenNat` \ regb ->
3309 getNewRegNCG IntRep `thenNat` \ tmp ->
3311 = case (isAny rega, isAny regb) of
3313 -> registerCode regb tmp `bind` \ code_b ->
3314 registerCode rega dst `bind` \ code_a ->
3317 instr (OpReg tmp) (OpReg dst)
3319 -> registerCode rega tmp `bind` \ code_a ->
3320 registerCodeF regb `bind` \ code_b ->
3321 registerNameF regb `bind` \ r_b ->
3324 instr (OpReg r_b) (OpReg tmp) `snocOL`
3325 MOV L (OpReg tmp) (OpReg dst)
3327 -> registerCode regb tmp `bind` \ code_b ->
3328 registerCodeF rega `bind` \ code_a ->
3329 registerNameF rega `bind` \ r_a ->
3332 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3333 instr (OpReg tmp) (OpReg dst)
3335 -> registerCodeF rega `bind` \ code_a ->
3336 registerNameF rega `bind` \ r_a ->
3337 registerCodeF regb `bind` \ code_b ->
3338 registerNameF regb `bind` \ r_b ->
3340 MOV L (OpReg r_a) (OpReg tmp) `appOL`
3342 instr (OpReg r_b) (OpReg tmp) `snocOL`
3343 MOV L (OpReg tmp) (OpReg dst)
3345 returnNat (Any IntRep mkcode)
3348 maybe_imm_a = maybeImm a
3349 is_imm_a = maybeToBool maybe_imm_a
3350 imm_a = case maybe_imm_a of Just imm -> imm
3352 maybe_imm_b = maybeImm b
3353 is_imm_b = maybeToBool maybe_imm_b
3354 imm_b = case maybe_imm_b of Just imm -> imm
3358 trivialUCode instr x
3359 = getRegister x `thenNat` \ register ->
3361 code__2 dst = let code = registerCode register dst
3362 src = registerName register dst
3364 if isFixed register && dst /= src
3365 then toOL [MOV L (OpReg src) (OpReg dst),
3367 else unitOL (instr (OpReg src))
3369 returnNat (Any IntRep code__2)
3372 trivialFCode pk instr x y
3373 = getRegister x `thenNat` \ register1 ->
3374 getRegister y `thenNat` \ register2 ->
3375 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3376 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3378 code1 = registerCode register1 tmp1
3379 src1 = registerName register1 tmp1
3381 code2 = registerCode register2 tmp2
3382 src2 = registerName register2 tmp2
3385 -- treat the common case specially: both operands in
3387 | isAny register1 && isAny register2
3390 instr (primRepToSize pk) src1 src2 dst
3392 -- be paranoid (and inefficient)
3394 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3396 instr (primRepToSize pk) tmp1 src2 dst
3398 returnNat (Any pk code__2)
3402 trivialUFCode pk instr x
3403 = getRegister x `thenNat` \ register ->
3404 getNewRegNCG pk `thenNat` \ tmp ->
3406 code = registerCode register tmp
3407 src = registerName register tmp
3408 code__2 dst = code `snocOL` instr src dst
3410 returnNat (Any pk code__2)
3412 #endif {- i386_TARGET_ARCH -}
3414 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3416 #if sparc_TARGET_ARCH
3418 trivialCode instr x (StInt y)
3420 = getRegister x `thenNat` \ register ->
3421 getNewRegNCG IntRep `thenNat` \ tmp ->
3423 code = registerCode register tmp
3424 src1 = registerName register tmp
3425 src2 = ImmInt (fromInteger y)
3426 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3428 returnNat (Any IntRep code__2)
3430 trivialCode instr x y
3431 = getRegister x `thenNat` \ register1 ->
3432 getRegister y `thenNat` \ register2 ->
3433 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3434 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3436 code1 = registerCode register1 tmp1
3437 src1 = registerName register1 tmp1
3438 code2 = registerCode register2 tmp2
3439 src2 = registerName register2 tmp2
3440 code__2 dst = code1 `appOL` code2 `snocOL`
3441 instr src1 (RIReg src2) dst
3443 returnNat (Any IntRep code__2)
3446 trivialFCode pk instr x y
3447 = getRegister x `thenNat` \ register1 ->
3448 getRegister y `thenNat` \ register2 ->
3449 getNewRegNCG (registerRep register1)
3451 getNewRegNCG (registerRep register2)
3453 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3455 promote x = FxTOy F DF x tmp
3457 pk1 = registerRep register1
3458 code1 = registerCode register1 tmp1
3459 src1 = registerName register1 tmp1
3461 pk2 = registerRep register2
3462 code2 = registerCode register2 tmp2
3463 src2 = registerName register2 tmp2
3467 code1 `appOL` code2 `snocOL`
3468 instr (primRepToSize pk) src1 src2 dst
3469 else if pk1 == FloatRep then
3470 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3471 instr DF tmp src2 dst
3473 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3474 instr DF src1 tmp dst
3476 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3479 trivialUCode instr x
3480 = getRegister x `thenNat` \ register ->
3481 getNewRegNCG IntRep `thenNat` \ tmp ->
3483 code = registerCode register tmp
3484 src = registerName register tmp
3485 code__2 dst = code `snocOL` instr (RIReg src) dst
3487 returnNat (Any IntRep code__2)
3490 trivialUFCode pk instr x
3491 = getRegister x `thenNat` \ register ->
3492 getNewRegNCG pk `thenNat` \ tmp ->
3494 code = registerCode register tmp
3495 src = registerName register tmp
3496 code__2 dst = code `snocOL` instr src dst
3498 returnNat (Any pk code__2)
3500 #endif {- sparc_TARGET_ARCH -}
3502 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3505 %************************************************************************
3507 \subsubsection{Coercing to/from integer/floating-point...}
3509 %************************************************************************
3511 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3512 conversions. We have to store temporaries in memory to move
3513 between the integer and the floating point register sets.
3515 @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
3516 pretend, on sparc at least, that double and float regs are seperate
3517 kinds, so the value has to be computed into one kind before being
3518 explicitly "converted" to live in the other kind.
3521 coerceInt2FP :: PrimRep -> StixExpr -> NatM Register
3522 coerceFP2Int :: PrimRep -> StixExpr -> NatM Register
3524 coerceDbl2Flt :: StixExpr -> NatM Register
3525 coerceFlt2Dbl :: StixExpr -> NatM Register
3529 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3531 #if alpha_TARGET_ARCH
3534 = getRegister x `thenNat` \ register ->
3535 getNewRegNCG IntRep `thenNat` \ reg ->
3537 code = registerCode register reg
3538 src = registerName register reg
3540 code__2 dst = code . mkSeqInstrs [
3542 LD TF dst (spRel 0),
3545 returnNat (Any DoubleRep code__2)
3549 = getRegister x `thenNat` \ register ->
3550 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3552 code = registerCode register tmp
3553 src = registerName register tmp
3555 code__2 dst = code . mkSeqInstrs [
3557 ST TF tmp (spRel 0),
3560 returnNat (Any IntRep code__2)
3562 #endif {- alpha_TARGET_ARCH -}
3564 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3566 #if i386_TARGET_ARCH
3569 = getRegister x `thenNat` \ register ->
3570 getNewRegNCG IntRep `thenNat` \ reg ->
3572 code = registerCode register reg
3573 src = registerName register reg
3574 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3575 code__2 dst = code `snocOL` opc src dst
3577 returnNat (Any pk code__2)
3580 coerceFP2Int fprep x
3581 = getRegister x `thenNat` \ register ->
3582 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3584 code = registerCode register tmp
3585 src = registerName register tmp
3586 pk = registerRep register
3588 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3589 code__2 dst = code `snocOL` opc src dst
3591 returnNat (Any IntRep code__2)
3594 coerceDbl2Flt x = panic "MachCode.coerceDbl2Flt: unused on x86"
3595 coerceFlt2Dbl x = panic "MachCode.coerceFlt2Dbl: unused on x86"
3597 #endif {- i386_TARGET_ARCH -}
3599 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3601 #if sparc_TARGET_ARCH
3604 = getRegister x `thenNat` \ register ->
3605 getNewRegNCG IntRep `thenNat` \ reg ->
3607 code = registerCode register reg
3608 src = registerName register reg
3610 code__2 dst = code `appOL` toOL [
3611 ST W src (spRel (-2)),
3612 LD W (spRel (-2)) dst,
3613 FxTOy W (primRepToSize pk) dst dst]
3615 returnNat (Any pk code__2)
3618 coerceFP2Int fprep x
3619 = ASSERT(fprep == DoubleRep || fprep == FloatRep)
3620 getRegister x `thenNat` \ register ->
3621 getNewRegNCG fprep `thenNat` \ reg ->
3622 getNewRegNCG FloatRep `thenNat` \ tmp ->
3624 code = registerCode register reg
3625 src = registerName register reg
3626 code__2 dst = code `appOL` toOL [
3627 FxTOy (primRepToSize fprep) W src tmp,
3628 ST W tmp (spRel (-2)),
3629 LD W (spRel (-2)) dst]
3631 returnNat (Any IntRep code__2)
3635 = getRegister x `thenNat` \ register ->
3636 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3637 let code = registerCode register tmp
3638 src = registerName register tmp
3640 returnNat (Any FloatRep
3641 (\dst -> code `snocOL` FxTOy DF F src dst))
3645 = getRegister x `thenNat` \ register ->
3646 getNewRegNCG FloatRep `thenNat` \ tmp ->
3647 let code = registerCode register tmp
3648 src = registerName register tmp
3650 returnNat (Any DoubleRep
3651 (\dst -> code `snocOL` FxTOy F DF src dst))
3653 #endif {- sparc_TARGET_ARCH -}
3655 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -