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
67 isLeft (Left _) = True
68 isLeft (Right _) = False
73 Code extractor for an entire stix tree---stix statement level.
76 stmtsToInstrs :: [StixStmt] -> NatM InstrBlock
78 = mapNat stmtToInstrs stmts `thenNat` \ instrss ->
79 returnNat (concatOL instrss)
82 stmtToInstrs :: StixStmt -> NatM InstrBlock
83 stmtToInstrs stmt = case stmt of
84 StComment s -> returnNat (unitOL (COMMENT s))
85 StSegment seg -> returnNat (unitOL (SEGMENT seg))
87 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
89 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
92 StLabel lab -> returnNat (unitOL (LABEL lab))
94 StJump dsts arg -> genJump dsts (derefDLL arg)
95 StCondJump lab arg -> genCondJump lab (derefDLL arg)
97 -- A call returning void, ie one done for its side-effects. Note
98 -- that this is the only StVoidable we handle.
99 StVoidable (StCall fn cconv VoidRep args)
100 -> genCCall fn cconv VoidRep (map derefDLL args)
102 StAssignMem pk addr src
103 | isFloatingRep pk -> assignMem_FltCode pk (derefDLL addr) (derefDLL src)
104 | ncg_target_is_32bit
105 && is64BitRep pk -> assignMem_I64Code (derefDLL addr) (derefDLL src)
106 | otherwise -> assignMem_IntCode pk (derefDLL addr) (derefDLL src)
107 StAssignReg pk reg src
108 | isFloatingRep pk -> assignReg_FltCode pk reg (derefDLL src)
109 | ncg_target_is_32bit
110 && is64BitRep pk -> assignReg_I64Code reg (derefDLL src)
111 | otherwise -> assignReg_IntCode pk reg (derefDLL src)
114 -- When falling through on the Alpha, we still have to load pv
115 -- with the address of the next routine, so that it can load gp.
116 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
120 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
121 returnNat (DATA (primRepToSize kind) imms
122 `consOL` concatOL codes)
124 getData :: StixExpr -> NatM (InstrBlock, Imm)
125 getData (StInt i) = returnNat (nilOL, ImmInteger i)
126 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
127 getData (StFloat d) = returnNat (nilOL, ImmFloat d)
128 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
129 getData (StString s) = panic "MachCode.stmtToInstrs: unlifted StString"
130 -- the linker can handle simple arithmetic...
131 getData (StIndex rep (StCLbl lbl) (StInt off)) =
133 ImmIndex lbl (fromInteger off * getPrimRepArrayElemSize rep))
135 -- Top-level lifted-out string. The segment will already have been set
136 -- (see Stix.liftStrings).
138 -> returnNat (unitOL (ASCII True (_UNPK_ str)))
141 other -> pprPanic "stmtToInstrs" (pprStixStmt other)
144 -- Walk a Stix tree, and insert dereferences to CLabels which are marked
145 -- as labelDynamic. stmt2Instrs calls derefDLL selectively, because
146 -- not all such CLabel occurrences need this dereferencing -- SRTs don't
148 derefDLL :: StixExpr -> StixExpr
150 | opt_Static -- short out the entire deal if not doing DLLs
157 StCLbl lbl -> if labelDynamic lbl
158 then StInd PtrRep (StCLbl lbl)
160 -- all the rest are boring
161 StIndex pk base offset -> StIndex pk (qq base) (qq offset)
162 StMachOp mop args -> StMachOp mop (map qq args)
163 StInd pk addr -> StInd pk (qq addr)
164 StCall (Left nm) cc pk args -> StCall (Left nm) cc pk (map qq args)
165 StCall (Right f) cc pk args -> StCall (Right (qq f)) cc pk (map qq args)
171 _ -> pprPanic "derefDLL: unhandled case"
175 %************************************************************************
177 \subsection{General things for putting together code sequences}
179 %************************************************************************
182 mangleIndexTree :: StixExpr -> StixExpr
184 mangleIndexTree (StIndex pk base (StInt i))
185 = StMachOp MO_Nat_Add [base, off]
187 off = StInt (i * toInteger (getPrimRepArrayElemSize pk))
189 mangleIndexTree (StIndex pk base off)
190 = StMachOp MO_Nat_Add [
193 in if s == 0 then off
194 else StMachOp MO_Nat_Shl [off, StInt (toInteger s)]
197 shift :: PrimRep -> Int
198 shift rep = case getPrimRepArrayElemSize rep of
203 other -> pprPanic "MachCode.mangleIndexTree.shift: unhandled rep size"
204 (Outputable.int other)
208 maybeImm :: StixExpr -> Maybe Imm
212 maybeImm (StIndex rep (StCLbl l) (StInt off))
213 = Just (ImmIndex l (fromInteger off * getPrimRepArrayElemSize rep))
215 | i >= toInteger (minBound::Int) && i <= toInteger (maxBound::Int)
216 = Just (ImmInt (fromInteger i))
218 = Just (ImmInteger i)
223 %************************************************************************
225 \subsection{The @Register64@ type}
227 %************************************************************************
229 Simple support for generating 64-bit code (ie, 64 bit values and 64
230 bit assignments) on 32-bit platforms. Unlike the main code generator
231 we merely shoot for generating working code as simply as possible, and
232 pay little attention to code quality. Specifically, there is no
233 attempt to deal cleverly with the fixed-vs-floating register
234 distinction; all values are generated into (pairs of) floating
235 registers, even if this would mean some redundant reg-reg moves as a
236 result. Only one of the VRegUniques is returned, since it will be
237 of the VRegUniqueLo form, and the upper-half VReg can be determined
238 by applying getHiVRegFromLo to it.
242 data ChildCode64 -- a.k.a "Register64"
245 VRegUnique -- unique for the lower 32-bit temporary
246 -- which contains the result; use getHiVRegFromLo to find
247 -- the other VRegUnique.
248 -- Rules of this simplified insn selection game are
249 -- therefore that the returned VRegUnique may be modified
251 assignMem_I64Code :: StixExpr -> StixExpr -> NatM InstrBlock
252 assignReg_I64Code :: StixReg -> StixExpr -> NatM InstrBlock
253 iselExpr64 :: StixExpr -> NatM ChildCode64
255 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
259 assignMem_I64Code addrTree valueTree
260 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
261 getRegister addrTree `thenNat` \ register_addr ->
262 getNewRegNCG IntRep `thenNat` \ t_addr ->
263 let rlo = VirtualRegI vrlo
264 rhi = getHiVRegFromLo rlo
265 code_addr = registerCode register_addr t_addr
266 reg_addr = registerName register_addr t_addr
267 -- Little-endian store
268 mov_lo = MOV L (OpReg rlo)
269 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
270 mov_hi = MOV L (OpReg rhi)
271 (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
273 returnNat (vcode `appOL` code_addr `snocOL` mov_lo `snocOL` mov_hi)
275 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
276 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
278 r_dst_lo = mkVReg u_dst IntRep
279 r_src_lo = VirtualRegI vr_src_lo
280 r_dst_hi = getHiVRegFromLo r_dst_lo
281 r_src_hi = getHiVRegFromLo r_src_lo
282 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
283 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
286 vcode `snocOL` mov_lo `snocOL` mov_hi
289 assignReg_I64Code lvalue valueTree
290 = pprPanic "assignReg_I64Code(i386): invalid lvalue"
295 iselExpr64 (StInd pk addrTree)
297 = getRegister addrTree `thenNat` \ register_addr ->
298 getNewRegNCG IntRep `thenNat` \ t_addr ->
299 getNewRegNCG IntRep `thenNat` \ rlo ->
300 let rhi = getHiVRegFromLo rlo
301 code_addr = registerCode register_addr t_addr
302 reg_addr = registerName register_addr t_addr
303 mov_lo = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 0)))
305 mov_hi = MOV L (OpAddr (AddrBaseIndex (Just reg_addr) Nothing (ImmInt 4)))
309 ChildCode64 (code_addr `snocOL` mov_lo `snocOL` mov_hi)
313 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
315 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
316 let r_dst_hi = getHiVRegFromLo r_dst_lo
317 r_src_lo = mkVReg vu IntRep
318 r_src_hi = getHiVRegFromLo r_src_lo
319 mov_lo = MOV L (OpReg r_src_lo) (OpReg r_dst_lo)
320 mov_hi = MOV L (OpReg r_src_hi) (OpReg r_dst_hi)
323 ChildCode64 (toOL [mov_lo, mov_hi]) (getVRegUnique r_dst_lo)
326 iselExpr64 (StCall fn cconv kind args)
328 = genCCall fn cconv kind args `thenNat` \ call ->
329 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
330 let r_dst_hi = getHiVRegFromLo r_dst_lo
331 mov_lo = MOV L (OpReg eax) (OpReg r_dst_lo)
332 mov_hi = MOV L (OpReg edx) (OpReg r_dst_hi)
335 ChildCode64 (call `snocOL` mov_lo `snocOL` mov_hi)
336 (getVRegUnique r_dst_lo)
340 = pprPanic "iselExpr64(i386)" (pprStixExpr expr)
342 #endif {- i386_TARGET_ARCH -}
344 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
346 #if sparc_TARGET_ARCH
348 assignMem_I64Code addrTree valueTree
349 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vrlo) ->
350 getRegister addrTree `thenNat` \ register_addr ->
351 getNewRegNCG IntRep `thenNat` \ t_addr ->
352 let rlo = VirtualRegI vrlo
353 rhi = getHiVRegFromLo rlo
354 code_addr = registerCode register_addr t_addr
355 reg_addr = registerName register_addr t_addr
357 mov_hi = ST W rhi (AddrRegImm reg_addr (ImmInt 0))
358 mov_lo = ST W rlo (AddrRegImm reg_addr (ImmInt 4))
360 returnNat (vcode `appOL` code_addr `snocOL` mov_hi `snocOL` mov_lo)
363 assignReg_I64Code (StixTemp (StixVReg u_dst pk)) valueTree
364 = iselExpr64 valueTree `thenNat` \ (ChildCode64 vcode vr_src_lo) ->
366 r_dst_lo = mkVReg u_dst IntRep
367 r_src_lo = VirtualRegI vr_src_lo
368 r_dst_hi = getHiVRegFromLo r_dst_lo
369 r_src_hi = getHiVRegFromLo r_src_lo
370 mov_lo = mkMOV r_src_lo r_dst_lo
371 mov_hi = mkMOV r_src_hi r_dst_hi
372 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
375 vcode `snocOL` mov_hi `snocOL` mov_lo
377 assignReg_I64Code lvalue valueTree
378 = pprPanic "assignReg_I64Code(sparc): invalid lvalue"
382 -- Don't delete this -- it's very handy for debugging.
384 -- | trace ("iselExpr64: " ++ showSDoc (pprStixExpr expr)) False
385 -- = panic "iselExpr64(???)"
387 iselExpr64 (StInd pk addrTree)
389 = getRegister addrTree `thenNat` \ register_addr ->
390 getNewRegNCG IntRep `thenNat` \ t_addr ->
391 getNewRegNCG IntRep `thenNat` \ rlo ->
392 let rhi = getHiVRegFromLo rlo
393 code_addr = registerCode register_addr t_addr
394 reg_addr = registerName register_addr t_addr
395 mov_hi = LD W (AddrRegImm reg_addr (ImmInt 0)) rhi
396 mov_lo = LD W (AddrRegImm reg_addr (ImmInt 4)) rlo
399 ChildCode64 (code_addr `snocOL` mov_hi `snocOL` mov_lo)
403 iselExpr64 (StReg (StixTemp (StixVReg vu pk)))
405 = getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
406 let r_dst_hi = getHiVRegFromLo r_dst_lo
407 r_src_lo = mkVReg vu IntRep
408 r_src_hi = getHiVRegFromLo r_src_lo
409 mov_lo = mkMOV r_src_lo r_dst_lo
410 mov_hi = mkMOV r_src_hi r_dst_hi
411 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
414 ChildCode64 (toOL [mov_hi, mov_lo]) (getVRegUnique r_dst_lo)
417 iselExpr64 (StCall fn cconv kind args)
419 = genCCall fn cconv kind args `thenNat` \ call ->
420 getNewRegNCG IntRep `thenNat` \ r_dst_lo ->
421 let r_dst_hi = getHiVRegFromLo r_dst_lo
422 mov_lo = mkMOV o0 r_dst_lo
423 mov_hi = mkMOV o1 r_dst_hi
424 mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
427 ChildCode64 (call `snocOL` mov_hi `snocOL` mov_lo)
428 (getVRegUnique r_dst_lo)
432 = pprPanic "iselExpr64(sparc)" (pprStixExpr expr)
434 #endif {- sparc_TARGET_ARCH -}
436 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
440 %************************************************************************
442 \subsection{The @Register@ type}
444 %************************************************************************
446 @Register@s passed up the tree. If the stix code forces the register
447 to live in a pre-decided machine register, it comes out as @Fixed@;
448 otherwise, it comes out as @Any@, and the parent can decide which
449 register to put it in.
453 = Fixed PrimRep Reg InstrBlock
454 | Any PrimRep (Reg -> InstrBlock)
456 registerCode :: Register -> Reg -> InstrBlock
457 registerCode (Fixed _ _ code) reg = code
458 registerCode (Any _ code) reg = code reg
460 registerCodeF (Fixed _ _ code) = code
461 registerCodeF (Any _ _) = panic "registerCodeF"
463 registerCodeA (Any _ code) = code
464 registerCodeA (Fixed _ _ _) = panic "registerCodeA"
466 registerName :: Register -> Reg -> Reg
467 registerName (Fixed _ reg _) _ = reg
468 registerName (Any _ _) reg = reg
470 registerNameF (Fixed _ reg _) = reg
471 registerNameF (Any _ _) = panic "registerNameF"
473 registerRep :: Register -> PrimRep
474 registerRep (Fixed pk _ _) = pk
475 registerRep (Any pk _) = pk
477 swizzleRegisterRep :: Register -> PrimRep -> Register
478 swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
479 swizzleRegisterRep (Any _ codefn) rep = Any rep codefn
481 {-# INLINE registerCode #-}
482 {-# INLINE registerCodeF #-}
483 {-# INLINE registerName #-}
484 {-# INLINE registerNameF #-}
485 {-# INLINE registerRep #-}
486 {-# INLINE isFixed #-}
489 isFixed, isAny :: Register -> Bool
490 isFixed (Fixed _ _ _) = True
491 isFixed (Any _ _) = False
493 isAny = not . isFixed
496 Generate code to get a subtree into a @Register@:
499 getRegisterReg :: StixReg -> NatM Register
500 getRegister :: StixExpr -> NatM Register
503 getRegisterReg (StixMagicId mid)
504 = case get_MagicId_reg_or_addr mid of
506 -> let pk = magicIdPrimRep mid
507 in returnNat (Fixed pk (RealReg rrno) nilOL)
509 -- By this stage, the only MagicIds remaining should be the
510 -- ones which map to a real machine register on this platform. Hence ...
511 -> pprPanic "getRegisterReg-memory" (pprMagicId mid)
513 getRegisterReg (StixTemp (StixVReg u pk))
514 = returnNat (Fixed pk (mkVReg u pk) nilOL)
518 -- Don't delete this -- it's very handy for debugging.
520 -- | trace ("getRegiste: " ++ showSDoc (pprStixExpr expr)) False
521 -- = panic "getRegister(???)"
523 getRegister (StReg reg)
526 getRegister tree@(StIndex _ _ _)
527 = getRegister (mangleIndexTree tree)
529 getRegister (StCall fn cconv kind args)
530 | not (ncg_target_is_32bit && is64BitRep kind)
531 = genCCall fn cconv kind args `thenNat` \ call ->
532 returnNat (Fixed kind reg call)
534 reg = if isFloatingRep kind
535 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
536 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
538 getRegister (StString s)
539 = getNatLabelNCG `thenNat` \ lbl ->
541 imm_lbl = ImmCLbl lbl
544 SEGMENT RoDataSegment,
546 ASCII True (_UNPK_ s),
548 #if alpha_TARGET_ARCH
549 LDA dst (AddrImm imm_lbl)
552 MOV L (OpImm imm_lbl) (OpReg dst)
554 #if sparc_TARGET_ARCH
555 SETHI (HI imm_lbl) dst,
556 OR False dst (RIImm (LO imm_lbl)) dst
560 returnNat (Any PtrRep code)
562 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
563 -- end of machine-"independent" bit; here we go on the rest...
565 #if alpha_TARGET_ARCH
567 getRegister (StDouble d)
568 = getNatLabelNCG `thenNat` \ lbl ->
569 getNewRegNCG PtrRep `thenNat` \ tmp ->
570 let code dst = mkSeqInstrs [
573 DATA TF [ImmLab (rational d)],
575 LDA tmp (AddrImm (ImmCLbl lbl)),
576 LD TF dst (AddrReg tmp)]
578 returnNat (Any DoubleRep code)
580 getRegister (StPrim primop [x]) -- unary PrimOps
582 IntNegOp -> trivialUCode (NEG Q False) x
584 NotOp -> trivialUCode NOT x
586 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
587 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
589 OrdOp -> coerceIntCode IntRep x
592 Float2IntOp -> coerceFP2Int x
593 Int2FloatOp -> coerceInt2FP pr x
594 Double2IntOp -> coerceFP2Int x
595 Int2DoubleOp -> coerceInt2FP pr x
597 Double2FloatOp -> coerceFltCode x
598 Float2DoubleOp -> coerceFltCode x
600 other_op -> getRegister (StCall fn CCallConv DoubleRep [x])
602 fn = case other_op of
603 FloatExpOp -> SLIT("exp")
604 FloatLogOp -> SLIT("log")
605 FloatSqrtOp -> SLIT("sqrt")
606 FloatSinOp -> SLIT("sin")
607 FloatCosOp -> SLIT("cos")
608 FloatTanOp -> SLIT("tan")
609 FloatAsinOp -> SLIT("asin")
610 FloatAcosOp -> SLIT("acos")
611 FloatAtanOp -> SLIT("atan")
612 FloatSinhOp -> SLIT("sinh")
613 FloatCoshOp -> SLIT("cosh")
614 FloatTanhOp -> SLIT("tanh")
615 DoubleExpOp -> SLIT("exp")
616 DoubleLogOp -> SLIT("log")
617 DoubleSqrtOp -> SLIT("sqrt")
618 DoubleSinOp -> SLIT("sin")
619 DoubleCosOp -> SLIT("cos")
620 DoubleTanOp -> SLIT("tan")
621 DoubleAsinOp -> SLIT("asin")
622 DoubleAcosOp -> SLIT("acos")
623 DoubleAtanOp -> SLIT("atan")
624 DoubleSinhOp -> SLIT("sinh")
625 DoubleCoshOp -> SLIT("cosh")
626 DoubleTanhOp -> SLIT("tanh")
628 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
630 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
632 CharGtOp -> trivialCode (CMP LTT) y x
633 CharGeOp -> trivialCode (CMP LE) y x
634 CharEqOp -> trivialCode (CMP EQQ) x y
635 CharNeOp -> int_NE_code x y
636 CharLtOp -> trivialCode (CMP LTT) x y
637 CharLeOp -> trivialCode (CMP LE) x y
639 IntGtOp -> trivialCode (CMP LTT) y x
640 IntGeOp -> trivialCode (CMP LE) y x
641 IntEqOp -> trivialCode (CMP EQQ) x y
642 IntNeOp -> int_NE_code x y
643 IntLtOp -> trivialCode (CMP LTT) x y
644 IntLeOp -> trivialCode (CMP LE) x y
646 WordGtOp -> trivialCode (CMP ULT) y x
647 WordGeOp -> trivialCode (CMP ULE) x y
648 WordEqOp -> trivialCode (CMP EQQ) x y
649 WordNeOp -> int_NE_code x y
650 WordLtOp -> trivialCode (CMP ULT) x y
651 WordLeOp -> trivialCode (CMP ULE) x y
653 AddrGtOp -> trivialCode (CMP ULT) y x
654 AddrGeOp -> trivialCode (CMP ULE) y x
655 AddrEqOp -> trivialCode (CMP EQQ) x y
656 AddrNeOp -> int_NE_code x y
657 AddrLtOp -> trivialCode (CMP ULT) x y
658 AddrLeOp -> trivialCode (CMP ULE) x y
660 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
661 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
662 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
663 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
664 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
665 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
667 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
668 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
669 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
670 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
671 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
672 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
674 IntAddOp -> trivialCode (ADD Q False) x y
675 IntSubOp -> trivialCode (SUB Q False) x y
676 IntMulOp -> trivialCode (MUL Q False) x y
677 IntQuotOp -> trivialCode (DIV Q False) x y
678 IntRemOp -> trivialCode (REM Q False) x y
680 WordAddOp -> trivialCode (ADD Q False) x y
681 WordSubOp -> trivialCode (SUB Q False) x y
682 WordMulOp -> trivialCode (MUL Q False) x y
683 WordQuotOp -> trivialCode (DIV Q True) x y
684 WordRemOp -> trivialCode (REM Q True) x y
686 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
687 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
688 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
689 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
691 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
692 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
693 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
694 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
696 AddrAddOp -> trivialCode (ADD Q False) x y
697 AddrSubOp -> trivialCode (SUB Q False) x y
698 AddrRemOp -> trivialCode (REM Q True) x y
700 AndOp -> trivialCode AND x y
701 OrOp -> trivialCode OR x y
702 XorOp -> trivialCode XOR x y
703 SllOp -> trivialCode SLL x y
704 SrlOp -> trivialCode SRL x y
706 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
707 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
708 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
710 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
711 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
713 {- ------------------------------------------------------------
714 Some bizarre special code for getting condition codes into
715 registers. Integer non-equality is a test for equality
716 followed by an XOR with 1. (Integer comparisons always set
717 the result register to 0 or 1.) Floating point comparisons of
718 any kind leave the result in a floating point register, so we
719 need to wrangle an integer register out of things.
721 int_NE_code :: StixTree -> StixTree -> NatM Register
724 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
725 getNewRegNCG IntRep `thenNat` \ tmp ->
727 code = registerCode register tmp
728 src = registerName register tmp
729 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
731 returnNat (Any IntRep code__2)
733 {- ------------------------------------------------------------
734 Comments for int_NE_code also apply to cmpF_code
737 :: (Reg -> Reg -> Reg -> Instr)
739 -> StixTree -> StixTree
742 cmpF_code instr cond x y
743 = trivialFCode pr instr x y `thenNat` \ register ->
744 getNewRegNCG DoubleRep `thenNat` \ tmp ->
745 getNatLabelNCG `thenNat` \ lbl ->
747 code = registerCode register tmp
748 result = registerName register tmp
750 code__2 dst = code . mkSeqInstrs [
751 OR zeroh (RIImm (ImmInt 1)) dst,
752 BF cond result (ImmCLbl lbl),
753 OR zeroh (RIReg zeroh) dst,
756 returnNat (Any IntRep code__2)
758 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
759 ------------------------------------------------------------
761 getRegister (StInd pk mem)
762 = getAmode mem `thenNat` \ amode ->
764 code = amodeCode amode
765 src = amodeAddr amode
766 size = primRepToSize pk
767 code__2 dst = code . mkSeqInstr (LD size dst src)
769 returnNat (Any pk code__2)
771 getRegister (StInt i)
774 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
776 returnNat (Any IntRep code)
779 code dst = mkSeqInstr (LDI Q dst src)
781 returnNat (Any IntRep code)
783 src = ImmInt (fromInteger i)
788 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
790 returnNat (Any PtrRep code)
793 imm__2 = case imm of Just x -> x
795 #endif {- alpha_TARGET_ARCH -}
797 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
801 getRegister (StFloat f)
802 = getNatLabelNCG `thenNat` \ lbl ->
803 let code dst = toOL [
808 GLD F (ImmAddr (ImmCLbl lbl) 0) dst
811 returnNat (Any FloatRep code)
814 getRegister (StDouble d)
817 = let code dst = unitOL (GLDZ dst)
818 in returnNat (Any DoubleRep code)
821 = let code dst = unitOL (GLD1 dst)
822 in returnNat (Any DoubleRep code)
825 = getNatLabelNCG `thenNat` \ lbl ->
826 let code dst = toOL [
829 DATA DF [ImmDouble d],
831 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
834 returnNat (Any DoubleRep code)
837 getRegister (StMachOp mop [x]) -- unary MachOps
839 MO_NatS_Neg -> trivialUCode (NEGI L) x
840 MO_Nat_Not -> trivialUCode (NOT L) x
841 MO_32U_to_8U -> trivialUCode (AND L (OpImm (ImmInt 255))) x
843 MO_Flt_Neg -> trivialUFCode FloatRep (GNEG F) x
844 MO_Dbl_Neg -> trivialUFCode DoubleRep (GNEG DF) x
846 MO_Flt_Sqrt -> trivialUFCode FloatRep (GSQRT F) x
847 MO_Dbl_Sqrt -> trivialUFCode DoubleRep (GSQRT DF) x
849 MO_Flt_Sin -> trivialUFCode FloatRep (GSIN F) x
850 MO_Dbl_Sin -> trivialUFCode DoubleRep (GSIN DF) x
852 MO_Flt_Cos -> trivialUFCode FloatRep (GCOS F) x
853 MO_Dbl_Cos -> trivialUFCode DoubleRep (GCOS DF) x
855 MO_Flt_Tan -> trivialUFCode FloatRep (GTAN F) x
856 MO_Dbl_Tan -> trivialUFCode DoubleRep (GTAN DF) x
858 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
859 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
860 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
861 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
863 -- Conversions which are a nop on x86
864 MO_NatS_to_32U -> conversionNop WordRep x
865 MO_32U_to_NatS -> conversionNop IntRep x
867 MO_NatU_to_NatS -> conversionNop IntRep x
868 MO_NatS_to_NatU -> conversionNop WordRep x
869 MO_NatP_to_NatU -> conversionNop WordRep x
870 MO_NatU_to_NatP -> conversionNop PtrRep x
871 MO_NatS_to_NatP -> conversionNop PtrRep x
872 MO_NatP_to_NatS -> conversionNop IntRep x
874 MO_Dbl_to_Flt -> conversionNop FloatRep x
875 MO_Flt_to_Dbl -> conversionNop DoubleRep x
877 -- sign-extending widenings
878 MO_8U_to_NatU -> integerExtend False 24 x
879 MO_8S_to_NatS -> integerExtend True 24 x
880 MO_16U_to_NatU -> integerExtend False 16 x
881 MO_16S_to_NatS -> integerExtend True 16 x
882 MO_8U_to_32U -> integerExtend False 24 x
886 (if is_float_op then demote else id)
887 (StCall (Left fn) CCallConv DoubleRep
888 [(if is_float_op then promote else id) x])
891 integerExtend signed nBits x
893 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
894 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
897 conversionNop new_rep expr
898 = getRegister expr `thenNat` \ e_code ->
899 returnNat (swizzleRegisterRep e_code new_rep)
901 promote x = StMachOp MO_Flt_to_Dbl [x]
902 demote x = StMachOp MO_Dbl_to_Flt [x]
905 MO_Flt_Exp -> (True, SLIT("exp"))
906 MO_Flt_Log -> (True, SLIT("log"))
908 MO_Flt_Asin -> (True, SLIT("asin"))
909 MO_Flt_Acos -> (True, SLIT("acos"))
910 MO_Flt_Atan -> (True, SLIT("atan"))
912 MO_Flt_Sinh -> (True, SLIT("sinh"))
913 MO_Flt_Cosh -> (True, SLIT("cosh"))
914 MO_Flt_Tanh -> (True, SLIT("tanh"))
916 MO_Dbl_Exp -> (False, SLIT("exp"))
917 MO_Dbl_Log -> (False, SLIT("log"))
919 MO_Dbl_Asin -> (False, SLIT("asin"))
920 MO_Dbl_Acos -> (False, SLIT("acos"))
921 MO_Dbl_Atan -> (False, SLIT("atan"))
923 MO_Dbl_Sinh -> (False, SLIT("sinh"))
924 MO_Dbl_Cosh -> (False, SLIT("cosh"))
925 MO_Dbl_Tanh -> (False, SLIT("tanh"))
927 other -> pprPanic "getRegister(x86) - binary StMachOp (2)"
931 getRegister (StMachOp mop [x, y]) -- dyadic MachOps
933 MO_32U_Gt -> condIntReg GTT x y
934 MO_32U_Ge -> condIntReg GE x y
935 MO_32U_Eq -> condIntReg EQQ x y
936 MO_32U_Ne -> condIntReg NE x y
937 MO_32U_Lt -> condIntReg LTT x y
938 MO_32U_Le -> condIntReg LE x y
940 MO_Nat_Eq -> condIntReg EQQ x y
941 MO_Nat_Ne -> condIntReg NE x y
943 MO_NatS_Gt -> condIntReg GTT x y
944 MO_NatS_Ge -> condIntReg GE x y
945 MO_NatS_Lt -> condIntReg LTT x y
946 MO_NatS_Le -> condIntReg LE x y
948 MO_NatU_Gt -> condIntReg GU x y
949 MO_NatU_Ge -> condIntReg GEU x y
950 MO_NatU_Lt -> condIntReg LU x y
951 MO_NatU_Le -> condIntReg LEU x y
953 MO_Flt_Gt -> condFltReg GTT x y
954 MO_Flt_Ge -> condFltReg GE x y
955 MO_Flt_Eq -> condFltReg EQQ x y
956 MO_Flt_Ne -> condFltReg NE x y
957 MO_Flt_Lt -> condFltReg LTT x y
958 MO_Flt_Le -> condFltReg LE x y
960 MO_Dbl_Gt -> condFltReg GTT x y
961 MO_Dbl_Ge -> condFltReg GE x y
962 MO_Dbl_Eq -> condFltReg EQQ x y
963 MO_Dbl_Ne -> condFltReg NE x y
964 MO_Dbl_Lt -> condFltReg LTT x y
965 MO_Dbl_Le -> condFltReg LE x y
967 MO_Nat_Add -> add_code L x y
968 MO_Nat_Sub -> sub_code L x y
969 MO_NatS_Quot -> trivialCode (IQUOT L) Nothing x y
970 MO_NatS_Rem -> trivialCode (IREM L) Nothing x y
971 MO_NatU_Quot -> trivialCode (QUOT L) Nothing x y
972 MO_NatU_Rem -> trivialCode (REM L) Nothing x y
973 MO_NatS_Mul -> let op = IMUL L in trivialCode op (Just op) x y
974 MO_NatU_Mul -> let op = MUL L in trivialCode op (Just op) x y
975 MO_NatS_MulMayOflo -> imulMayOflo x y
977 MO_Flt_Add -> trivialFCode FloatRep GADD x y
978 MO_Flt_Sub -> trivialFCode FloatRep GSUB x y
979 MO_Flt_Mul -> trivialFCode FloatRep GMUL x y
980 MO_Flt_Div -> trivialFCode FloatRep GDIV x y
982 MO_Dbl_Add -> trivialFCode DoubleRep GADD x y
983 MO_Dbl_Sub -> trivialFCode DoubleRep GSUB x y
984 MO_Dbl_Mul -> trivialFCode DoubleRep GMUL x y
985 MO_Dbl_Div -> trivialFCode DoubleRep GDIV x y
987 MO_Nat_And -> let op = AND L in trivialCode op (Just op) x y
988 MO_Nat_Or -> let op = OR L in trivialCode op (Just op) x y
989 MO_Nat_Xor -> let op = XOR L in trivialCode op (Just op) x y
991 {- Shift ops on x86s have constraints on their source, it
992 either has to be Imm, CL or 1
993 => trivialCode's is not restrictive enough (sigh.)
995 MO_Nat_Shl -> shift_code (SHL L) x y {-False-}
996 MO_Nat_Shr -> shift_code (SHR L) x y {-False-}
997 MO_Nat_Sar -> shift_code (SAR L) x y {-False-}
999 MO_Flt_Pwr -> getRegister (demote
1000 (StCall (Left SLIT("pow")) CCallConv DoubleRep
1001 [promote x, promote y])
1003 MO_Dbl_Pwr -> getRegister (StCall (Left SLIT("pow")) CCallConv DoubleRep
1005 other -> pprPanic "getRegister(x86) - binary StMachOp (1)" (pprMachOp mop)
1007 promote x = StMachOp MO_Flt_to_Dbl [x]
1008 demote x = StMachOp MO_Dbl_to_Flt [x]
1010 --------------------
1011 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1013 = getNewRegNCG IntRep `thenNat` \ t1 ->
1014 getNewRegNCG IntRep `thenNat` \ t2 ->
1015 getNewRegNCG IntRep `thenNat` \ res_lo ->
1016 getNewRegNCG IntRep `thenNat` \ res_hi ->
1017 getRegister a1 `thenNat` \ reg1 ->
1018 getRegister a2 `thenNat` \ reg2 ->
1019 let code1 = registerCode reg1 t1
1020 code2 = registerCode reg2 t2
1021 src1 = registerName reg1 t1
1022 src2 = registerName reg2 t2
1023 code dst = code1 `appOL` code2 `appOL`
1025 MOV L (OpReg src1) (OpReg res_hi),
1026 MOV L (OpReg src2) (OpReg res_lo),
1027 IMUL64 res_hi res_lo, -- result in res_hi:res_lo
1028 SAR L (ImmInt 31) (OpReg res_lo), -- sign extend lower part
1029 SUB L (OpReg res_hi) (OpReg res_lo), -- compare against upper
1030 MOV L (OpReg res_lo) (OpReg dst)
1031 -- dst==0 if high part == sign extended low part
1034 returnNat (Any IntRep code)
1036 --------------------
1037 shift_code :: (Imm -> Operand -> Instr)
1042 {- Case1: shift length as immediate -}
1043 -- Code is the same as the first eq. for trivialCode -- sigh.
1044 shift_code instr x y{-amount-}
1046 = getRegister x `thenNat` \ regx ->
1049 then registerCodeA regx dst `bind` \ code_x ->
1051 instr imm__2 (OpReg dst)
1052 else registerCodeF regx `bind` \ code_x ->
1053 registerNameF regx `bind` \ r_x ->
1055 MOV L (OpReg r_x) (OpReg dst) `snocOL`
1056 instr imm__2 (OpReg dst)
1058 returnNat (Any IntRep mkcode)
1061 imm__2 = case imm of Just x -> x
1063 {- Case2: shift length is complex (non-immediate) -}
1064 -- Since ECX is always used as a spill temporary, we can't
1065 -- use it here to do non-immediate shifts. No big deal --
1066 -- they are only very rare, and we can use an equivalent
1067 -- test-and-jump sequence which doesn't use ECX.
1068 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
1069 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
1070 shift_code instr x y{-amount-}
1071 = getRegister x `thenNat` \ register1 ->
1072 getRegister y `thenNat` \ register2 ->
1073 getNatLabelNCG `thenNat` \ lbl_test3 ->
1074 getNatLabelNCG `thenNat` \ lbl_test2 ->
1075 getNatLabelNCG `thenNat` \ lbl_test1 ->
1076 getNatLabelNCG `thenNat` \ lbl_test0 ->
1077 getNatLabelNCG `thenNat` \ lbl_after ->
1078 getNewRegNCG IntRep `thenNat` \ tmp ->
1080 = let src_val = registerName register1 dst
1081 code_val = registerCode register1 dst
1082 src_amt = registerName register2 tmp
1083 code_amt = registerCode register2 tmp
1088 MOV L (OpReg src_amt) r_tmp `appOL`
1090 MOV L (OpReg src_val) r_dst `appOL`
1092 COMMENT (_PK_ "begin shift sequence"),
1093 MOV L (OpReg src_val) r_dst,
1094 MOV L (OpReg src_amt) r_tmp,
1096 BT L (ImmInt 4) r_tmp,
1098 instr (ImmInt 16) r_dst,
1101 BT L (ImmInt 3) r_tmp,
1103 instr (ImmInt 8) r_dst,
1106 BT L (ImmInt 2) r_tmp,
1108 instr (ImmInt 4) r_dst,
1111 BT L (ImmInt 1) r_tmp,
1113 instr (ImmInt 2) r_dst,
1116 BT L (ImmInt 0) r_tmp,
1118 instr (ImmInt 1) r_dst,
1121 COMMENT (_PK_ "end shift sequence")
1124 returnNat (Any IntRep code__2)
1126 --------------------
1127 add_code :: Size -> StixExpr -> StixExpr -> NatM Register
1129 add_code sz x (StInt y)
1130 = getRegister x `thenNat` \ register ->
1131 getNewRegNCG IntRep `thenNat` \ tmp ->
1133 code = registerCode register tmp
1134 src1 = registerName register tmp
1135 src2 = ImmInt (fromInteger y)
1138 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1141 returnNat (Any IntRep code__2)
1143 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
1145 --------------------
1146 sub_code :: Size -> StixExpr -> StixExpr -> NatM Register
1148 sub_code sz x (StInt y)
1149 = getRegister x `thenNat` \ register ->
1150 getNewRegNCG IntRep `thenNat` \ tmp ->
1152 code = registerCode register tmp
1153 src1 = registerName register tmp
1154 src2 = ImmInt (-(fromInteger y))
1157 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
1160 returnNat (Any IntRep code__2)
1162 sub_code sz x y = trivialCode (SUB sz) Nothing x y
1164 getRegister (StInd pk mem)
1165 | not (is64BitRep pk)
1166 = getAmode mem `thenNat` \ amode ->
1168 code = amodeCode amode
1169 src = amodeAddr amode
1170 size = primRepToSize pk
1171 code__2 dst = code `snocOL`
1172 if pk == DoubleRep || pk == FloatRep
1173 then GLD size src dst
1181 (OpAddr src) (OpReg dst)
1183 returnNat (Any pk code__2)
1185 getRegister (StInt i)
1187 src = ImmInt (fromInteger i)
1190 = unitOL (XOR L (OpReg dst) (OpReg dst))
1192 = unitOL (MOV L (OpImm src) (OpReg dst))
1194 returnNat (Any IntRep code)
1198 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
1200 returnNat (Any PtrRep code)
1202 = ncgPrimopMoan "getRegister(x86)" (pprStixExpr leaf)
1205 imm__2 = case imm of Just x -> x
1207 #endif {- i386_TARGET_ARCH -}
1209 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1211 #if sparc_TARGET_ARCH
1213 getRegister (StFloat d)
1214 = getNatLabelNCG `thenNat` \ lbl ->
1215 getNewRegNCG PtrRep `thenNat` \ tmp ->
1216 let code dst = toOL [
1217 SEGMENT DataSegment,
1219 DATA F [ImmFloat d],
1220 SEGMENT TextSegment,
1221 SETHI (HI (ImmCLbl lbl)) tmp,
1222 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1224 returnNat (Any FloatRep code)
1226 getRegister (StDouble d)
1227 = getNatLabelNCG `thenNat` \ lbl ->
1228 getNewRegNCG PtrRep `thenNat` \ tmp ->
1229 let code dst = toOL [
1230 SEGMENT DataSegment,
1232 DATA DF [ImmDouble d],
1233 SEGMENT TextSegment,
1234 SETHI (HI (ImmCLbl lbl)) tmp,
1235 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1237 returnNat (Any DoubleRep code)
1240 getRegister (StMachOp mop [x]) -- unary PrimOps
1242 MO_NatS_Neg -> trivialUCode (SUB False False g0) x
1243 MO_Nat_Not -> trivialUCode (XNOR False g0) x
1245 MO_Flt_Neg -> trivialUFCode FloatRep (FNEG F) x
1246 MO_Dbl_Neg -> trivialUFCode DoubleRep (FNEG DF) x
1248 MO_Dbl_to_Flt -> coerceDbl2Flt x
1249 MO_Flt_to_Dbl -> coerceFlt2Dbl x
1251 MO_Flt_to_NatS -> coerceFP2Int FloatRep x
1252 MO_NatS_to_Flt -> coerceInt2FP FloatRep x
1253 MO_Dbl_to_NatS -> coerceFP2Int DoubleRep x
1254 MO_NatS_to_Dbl -> coerceInt2FP DoubleRep x
1256 -- Conversions which are a nop on sparc
1257 MO_32U_to_NatS -> conversionNop IntRep x
1258 MO_NatS_to_32U -> conversionNop WordRep x
1260 MO_NatU_to_NatS -> conversionNop IntRep x
1261 MO_NatS_to_NatU -> conversionNop WordRep x
1262 MO_NatP_to_NatU -> conversionNop WordRep x
1263 MO_NatU_to_NatP -> conversionNop PtrRep x
1264 MO_NatS_to_NatP -> conversionNop PtrRep x
1265 MO_NatP_to_NatS -> conversionNop IntRep x
1267 -- sign-extending widenings
1268 MO_8U_to_32U -> integerExtend False 24 x
1269 MO_8U_to_NatU -> integerExtend False 24 x
1270 MO_8S_to_NatS -> integerExtend True 24 x
1271 MO_16U_to_NatU -> integerExtend False 16 x
1272 MO_16S_to_NatS -> integerExtend True 16 x
1275 let fixed_x = if is_float_op -- promote to double
1276 then StMachOp MO_Flt_to_Dbl [x]
1279 getRegister (StCall (Left fn) CCallConv DoubleRep [fixed_x])
1281 integerExtend signed nBits x
1283 StMachOp (if signed then MO_Nat_Sar else MO_Nat_Shr)
1284 [StMachOp MO_Nat_Shl [x, StInt nBits], StInt nBits]
1286 conversionNop new_rep expr
1287 = getRegister expr `thenNat` \ e_code ->
1288 returnNat (swizzleRegisterRep e_code new_rep)
1292 MO_Flt_Exp -> (True, SLIT("exp"))
1293 MO_Flt_Log -> (True, SLIT("log"))
1294 MO_Flt_Sqrt -> (True, SLIT("sqrt"))
1296 MO_Flt_Sin -> (True, SLIT("sin"))
1297 MO_Flt_Cos -> (True, SLIT("cos"))
1298 MO_Flt_Tan -> (True, SLIT("tan"))
1300 MO_Flt_Asin -> (True, SLIT("asin"))
1301 MO_Flt_Acos -> (True, SLIT("acos"))
1302 MO_Flt_Atan -> (True, SLIT("atan"))
1304 MO_Flt_Sinh -> (True, SLIT("sinh"))
1305 MO_Flt_Cosh -> (True, SLIT("cosh"))
1306 MO_Flt_Tanh -> (True, SLIT("tanh"))
1308 MO_Dbl_Exp -> (False, SLIT("exp"))
1309 MO_Dbl_Log -> (False, SLIT("log"))
1310 MO_Dbl_Sqrt -> (False, SLIT("sqrt"))
1312 MO_Dbl_Sin -> (False, SLIT("sin"))
1313 MO_Dbl_Cos -> (False, SLIT("cos"))
1314 MO_Dbl_Tan -> (False, SLIT("tan"))
1316 MO_Dbl_Asin -> (False, SLIT("asin"))
1317 MO_Dbl_Acos -> (False, SLIT("acos"))
1318 MO_Dbl_Atan -> (False, SLIT("atan"))
1320 MO_Dbl_Sinh -> (False, SLIT("sinh"))
1321 MO_Dbl_Cosh -> (False, SLIT("cosh"))
1322 MO_Dbl_Tanh -> (False, SLIT("tanh"))
1324 other -> pprPanic "getRegister(sparc) - binary StMachOp (2)"
1328 getRegister (StMachOp mop [x, y]) -- dyadic PrimOps
1330 MO_32U_Gt -> condIntReg GTT x y
1331 MO_32U_Ge -> condIntReg GE x y
1332 MO_32U_Eq -> condIntReg EQQ x y
1333 MO_32U_Ne -> condIntReg NE x y
1334 MO_32U_Lt -> condIntReg LTT x y
1335 MO_32U_Le -> condIntReg LE x y
1337 MO_Nat_Eq -> condIntReg EQQ x y
1338 MO_Nat_Ne -> condIntReg NE x y
1340 MO_NatS_Gt -> condIntReg GTT x y
1341 MO_NatS_Ge -> condIntReg GE x y
1342 MO_NatS_Lt -> condIntReg LTT x y
1343 MO_NatS_Le -> condIntReg LE x y
1345 MO_NatU_Gt -> condIntReg GU x y
1346 MO_NatU_Ge -> condIntReg GEU x y
1347 MO_NatU_Lt -> condIntReg LU x y
1348 MO_NatU_Le -> condIntReg LEU x y
1350 MO_Flt_Gt -> condFltReg GTT x y
1351 MO_Flt_Ge -> condFltReg GE x y
1352 MO_Flt_Eq -> condFltReg EQQ x y
1353 MO_Flt_Ne -> condFltReg NE x y
1354 MO_Flt_Lt -> condFltReg LTT x y
1355 MO_Flt_Le -> condFltReg LE x y
1357 MO_Dbl_Gt -> condFltReg GTT x y
1358 MO_Dbl_Ge -> condFltReg GE x y
1359 MO_Dbl_Eq -> condFltReg EQQ x y
1360 MO_Dbl_Ne -> condFltReg NE x y
1361 MO_Dbl_Lt -> condFltReg LTT x y
1362 MO_Dbl_Le -> condFltReg LE x y
1364 MO_Nat_Add -> trivialCode (ADD False False) x y
1365 MO_Nat_Sub -> trivialCode (SUB False False) x y
1367 MO_NatS_Mul -> trivialCode (SMUL False) x y
1368 MO_NatU_Mul -> trivialCode (UMUL False) x y
1369 MO_NatS_MulMayOflo -> imulMayOflo x y
1371 -- ToDo: teach about V8+ SPARC div instructions
1372 MO_NatS_Quot -> idiv SLIT(".div") x y
1373 MO_NatS_Rem -> idiv SLIT(".rem") x y
1374 MO_NatU_Quot -> idiv SLIT(".udiv") x y
1375 MO_NatU_Rem -> idiv SLIT(".urem") x y
1377 MO_Flt_Add -> trivialFCode FloatRep FADD x y
1378 MO_Flt_Sub -> trivialFCode FloatRep FSUB x y
1379 MO_Flt_Mul -> trivialFCode FloatRep FMUL x y
1380 MO_Flt_Div -> trivialFCode FloatRep FDIV x y
1382 MO_Dbl_Add -> trivialFCode DoubleRep FADD x y
1383 MO_Dbl_Sub -> trivialFCode DoubleRep FSUB x y
1384 MO_Dbl_Mul -> trivialFCode DoubleRep FMUL x y
1385 MO_Dbl_Div -> trivialFCode DoubleRep FDIV x y
1387 MO_Nat_And -> trivialCode (AND False) x y
1388 MO_Nat_Or -> trivialCode (OR False) x y
1389 MO_Nat_Xor -> trivialCode (XOR False) x y
1391 MO_Nat_Shl -> trivialCode SLL x y
1392 MO_Nat_Shr -> trivialCode SRL x y
1393 MO_Nat_Sar -> trivialCode SRA x y
1395 MO_Flt_Pwr -> getRegister (StCall (Left SLIT("pow")) CCallConv DoubleRep
1396 [promote x, promote y])
1397 where promote x = StMachOp MO_Flt_to_Dbl [x]
1398 MO_Dbl_Pwr -> getRegister (StCall (Left SLIT("pow")) CCallConv DoubleRep
1401 other -> pprPanic "getRegister(sparc) - binary StMachOp (1)" (pprMachOp mop)
1403 idiv fn x y = getRegister (StCall (Left fn) CCallConv IntRep [x, y])
1405 --------------------
1406 imulMayOflo :: StixExpr -> StixExpr -> NatM Register
1408 = getNewRegNCG IntRep `thenNat` \ t1 ->
1409 getNewRegNCG IntRep `thenNat` \ t2 ->
1410 getNewRegNCG IntRep `thenNat` \ res_lo ->
1411 getNewRegNCG IntRep `thenNat` \ res_hi ->
1412 getRegister a1 `thenNat` \ reg1 ->
1413 getRegister a2 `thenNat` \ reg2 ->
1414 let code1 = registerCode reg1 t1
1415 code2 = registerCode reg2 t2
1416 src1 = registerName reg1 t1
1417 src2 = registerName reg2 t2
1418 code dst = code1 `appOL` code2 `appOL`
1420 SMUL False src1 (RIReg src2) res_lo,
1422 SRA res_lo (RIImm (ImmInt 31)) res_lo,
1423 SUB False False res_lo (RIReg res_hi) dst
1426 returnNat (Any IntRep code)
1428 getRegister (StInd pk mem)
1429 = getAmode mem `thenNat` \ amode ->
1431 code = amodeCode amode
1432 src = amodeAddr amode
1433 size = primRepToSize pk
1434 code__2 dst = code `snocOL` LD size src dst
1436 returnNat (Any pk code__2)
1438 getRegister (StInt i)
1441 src = ImmInt (fromInteger i)
1442 code dst = unitOL (OR False g0 (RIImm src) dst)
1444 returnNat (Any IntRep code)
1450 SETHI (HI imm__2) dst,
1451 OR False dst (RIImm (LO imm__2)) dst]
1453 returnNat (Any PtrRep code)
1455 = ncgPrimopMoan "getRegister(sparc)" (pprStixExpr leaf)
1458 imm__2 = case imm of Just x -> x
1460 #endif {- sparc_TARGET_ARCH -}
1462 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1466 %************************************************************************
1468 \subsection{The @Amode@ type}
1470 %************************************************************************
1472 @Amode@s: Memory addressing modes passed up the tree.
1474 data Amode = Amode MachRegsAddr InstrBlock
1476 amodeAddr (Amode addr _) = addr
1477 amodeCode (Amode _ code) = code
1480 Now, given a tree (the argument to an StInd) that references memory,
1481 produce a suitable addressing mode.
1483 A Rule of the Game (tm) for Amodes: use of the addr bit must
1484 immediately follow use of the code part, since the code part puts
1485 values in registers which the addr then refers to. So you can't put
1486 anything in between, lest it overwrite some of those registers. If
1487 you need to do some other computation between the code part and use of
1488 the addr bit, first store the effective address from the amode in a
1489 temporary, then do the other computation, and then use the temporary:
1493 ... other computation ...
1497 getAmode :: StixExpr -> NatM Amode
1499 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1501 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1503 #if alpha_TARGET_ARCH
1505 getAmode (StPrim IntSubOp [x, StInt i])
1506 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1507 getRegister x `thenNat` \ register ->
1509 code = registerCode register tmp
1510 reg = registerName register tmp
1511 off = ImmInt (-(fromInteger i))
1513 returnNat (Amode (AddrRegImm reg off) code)
1515 getAmode (StPrim IntAddOp [x, StInt i])
1516 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1517 getRegister x `thenNat` \ register ->
1519 code = registerCode register tmp
1520 reg = registerName register tmp
1521 off = ImmInt (fromInteger i)
1523 returnNat (Amode (AddrRegImm reg off) code)
1527 = returnNat (Amode (AddrImm imm__2) id)
1530 imm__2 = case imm of Just x -> x
1533 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1534 getRegister other `thenNat` \ register ->
1536 code = registerCode register tmp
1537 reg = registerName register tmp
1539 returnNat (Amode (AddrReg reg) code)
1541 #endif {- alpha_TARGET_ARCH -}
1543 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1545 #if i386_TARGET_ARCH
1547 -- This is all just ridiculous, since it carefully undoes
1548 -- what mangleIndexTree has just done.
1549 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1550 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1551 getRegister x `thenNat` \ register ->
1553 code = registerCode register tmp
1554 reg = registerName register tmp
1555 off = ImmInt (-(fromInteger i))
1557 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1559 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1561 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1564 imm__2 = case imm of Just x -> x
1566 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1567 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1568 getRegister x `thenNat` \ register ->
1570 code = registerCode register tmp
1571 reg = registerName register tmp
1572 off = ImmInt (fromInteger i)
1574 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1576 getAmode (StMachOp MO_Nat_Add [x, StMachOp MO_Nat_Shl [y, StInt shift]])
1577 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1578 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1579 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1580 getRegister x `thenNat` \ register1 ->
1581 getRegister y `thenNat` \ register2 ->
1583 code1 = registerCode register1 tmp1
1584 reg1 = registerName register1 tmp1
1585 code2 = registerCode register2 tmp2
1586 reg2 = registerName register2 tmp2
1587 code__2 = code1 `appOL` code2
1588 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1590 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1595 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1598 imm__2 = case imm of Just x -> x
1601 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1602 getRegister other `thenNat` \ register ->
1604 code = registerCode register tmp
1605 reg = registerName register tmp
1607 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1609 #endif {- i386_TARGET_ARCH -}
1611 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1613 #if sparc_TARGET_ARCH
1615 getAmode (StMachOp MO_Nat_Sub [x, StInt i])
1617 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1618 getRegister x `thenNat` \ register ->
1620 code = registerCode register tmp
1621 reg = registerName register tmp
1622 off = ImmInt (-(fromInteger i))
1624 returnNat (Amode (AddrRegImm reg off) code)
1627 getAmode (StMachOp MO_Nat_Add [x, StInt i])
1629 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1630 getRegister x `thenNat` \ register ->
1632 code = registerCode register tmp
1633 reg = registerName register tmp
1634 off = ImmInt (fromInteger i)
1636 returnNat (Amode (AddrRegImm reg off) code)
1638 getAmode (StMachOp MO_Nat_Add [x, y])
1639 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1640 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1641 getRegister x `thenNat` \ register1 ->
1642 getRegister y `thenNat` \ register2 ->
1644 code1 = registerCode register1 tmp1
1645 reg1 = registerName register1 tmp1
1646 code2 = registerCode register2 tmp2
1647 reg2 = registerName register2 tmp2
1648 code__2 = code1 `appOL` code2
1650 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1654 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1656 code = unitOL (SETHI (HI imm__2) tmp)
1658 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1661 imm__2 = case imm of Just x -> x
1664 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1665 getRegister other `thenNat` \ register ->
1667 code = registerCode register tmp
1668 reg = registerName register tmp
1671 returnNat (Amode (AddrRegImm reg off) code)
1673 #endif {- sparc_TARGET_ARCH -}
1675 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1678 %************************************************************************
1680 \subsection{The @CondCode@ type}
1682 %************************************************************************
1684 Condition codes passed up the tree.
1686 data CondCode = CondCode Bool Cond InstrBlock
1688 condName (CondCode _ cond _) = cond
1689 condFloat (CondCode is_float _ _) = is_float
1690 condCode (CondCode _ _ code) = code
1693 Set up a condition code for a conditional branch.
1696 getCondCode :: StixExpr -> NatM CondCode
1698 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1700 #if alpha_TARGET_ARCH
1701 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1702 #endif {- alpha_TARGET_ARCH -}
1704 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1706 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1707 -- yes, they really do seem to want exactly the same!
1709 getCondCode (StMachOp mop [x, y])
1711 MO_32U_Gt -> condIntCode GTT x y
1712 MO_32U_Ge -> condIntCode GE x y
1713 MO_32U_Eq -> condIntCode EQQ x y
1714 MO_32U_Ne -> condIntCode NE x y
1715 MO_32U_Lt -> condIntCode LTT x y
1716 MO_32U_Le -> condIntCode LE x y
1718 MO_Nat_Eq -> condIntCode EQQ x y
1719 MO_Nat_Ne -> condIntCode NE x y
1721 MO_NatS_Gt -> condIntCode GTT x y
1722 MO_NatS_Ge -> condIntCode GE x y
1723 MO_NatS_Lt -> condIntCode LTT x y
1724 MO_NatS_Le -> condIntCode LE x y
1726 MO_NatU_Gt -> condIntCode GU x y
1727 MO_NatU_Ge -> condIntCode GEU x y
1728 MO_NatU_Lt -> condIntCode LU x y
1729 MO_NatU_Le -> condIntCode LEU x y
1731 MO_Flt_Gt -> condFltCode GTT x y
1732 MO_Flt_Ge -> condFltCode GE x y
1733 MO_Flt_Eq -> condFltCode EQQ x y
1734 MO_Flt_Ne -> condFltCode NE x y
1735 MO_Flt_Lt -> condFltCode LTT x y
1736 MO_Flt_Le -> condFltCode LE x y
1738 MO_Dbl_Gt -> condFltCode GTT x y
1739 MO_Dbl_Ge -> condFltCode GE x y
1740 MO_Dbl_Eq -> condFltCode EQQ x y
1741 MO_Dbl_Ne -> condFltCode NE x y
1742 MO_Dbl_Lt -> condFltCode LTT x y
1743 MO_Dbl_Le -> condFltCode LE x y
1745 other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
1747 getCondCode other = pprPanic "getCondCode(2)(x86,sparc)" (pprStixExpr other)
1749 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1751 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1756 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1757 passed back up the tree.
1760 condIntCode, condFltCode :: Cond -> StixExpr -> StixExpr -> NatM CondCode
1762 #if alpha_TARGET_ARCH
1763 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1764 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1765 #endif {- alpha_TARGET_ARCH -}
1767 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1768 #if i386_TARGET_ARCH
1770 -- memory vs immediate
1771 condIntCode cond (StInd pk x) y
1772 | Just i <- maybeImm y
1773 = getAmode x `thenNat` \ amode ->
1775 code1 = amodeCode amode
1776 x__2 = amodeAddr amode
1777 sz = primRepToSize pk
1778 code__2 = code1 `snocOL`
1779 CMP sz (OpImm i) (OpAddr x__2)
1781 returnNat (CondCode False cond code__2)
1784 condIntCode cond x (StInt 0)
1785 = getRegister x `thenNat` \ register1 ->
1786 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1788 code1 = registerCode register1 tmp1
1789 src1 = registerName register1 tmp1
1790 code__2 = code1 `snocOL`
1791 TEST L (OpReg src1) (OpReg src1)
1793 returnNat (CondCode False cond code__2)
1795 -- anything vs immediate
1796 condIntCode cond x y
1797 | Just i <- maybeImm y
1798 = getRegister x `thenNat` \ register1 ->
1799 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1801 code1 = registerCode register1 tmp1
1802 src1 = registerName register1 tmp1
1803 code__2 = code1 `snocOL`
1804 CMP L (OpImm i) (OpReg src1)
1806 returnNat (CondCode False cond code__2)
1808 -- memory vs anything
1809 condIntCode cond (StInd pk x) y
1810 = getAmode x `thenNat` \ amode_x ->
1811 getRegister y `thenNat` \ reg_y ->
1812 getNewRegNCG IntRep `thenNat` \ tmp ->
1814 c_x = amodeCode amode_x
1815 am_x = amodeAddr amode_x
1816 c_y = registerCode reg_y tmp
1817 r_y = registerName reg_y tmp
1818 sz = primRepToSize pk
1820 -- optimisation: if there's no code for x, just an amode,
1821 -- use whatever reg y winds up in. Assumes that c_y doesn't
1822 -- clobber any regs in the amode am_x, which I'm not sure is
1823 -- justified. The otherwise clause makes the same assumption.
1824 code__2 | isNilOL c_x
1826 CMP sz (OpReg r_y) (OpAddr am_x)
1830 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1832 CMP sz (OpReg tmp) (OpAddr am_x)
1834 returnNat (CondCode False cond code__2)
1836 -- anything vs memory
1838 condIntCode cond y (StInd pk x)
1839 = getAmode x `thenNat` \ amode_x ->
1840 getRegister y `thenNat` \ reg_y ->
1841 getNewRegNCG IntRep `thenNat` \ tmp ->
1843 c_x = amodeCode amode_x
1844 am_x = amodeAddr amode_x
1845 c_y = registerCode reg_y tmp
1846 r_y = registerName reg_y tmp
1847 sz = primRepToSize pk
1848 -- same optimisation and nagging doubts as previous clause
1849 code__2 | isNilOL c_x
1851 CMP sz (OpAddr am_x) (OpReg r_y)
1855 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1857 CMP sz (OpAddr am_x) (OpReg tmp)
1859 returnNat (CondCode False cond code__2)
1861 -- anything vs anything
1862 condIntCode cond x y
1863 = getRegister x `thenNat` \ register1 ->
1864 getRegister y `thenNat` \ register2 ->
1865 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1866 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1868 code1 = registerCode register1 tmp1
1869 src1 = registerName register1 tmp1
1870 code2 = registerCode register2 tmp2
1871 src2 = registerName register2 tmp2
1872 code__2 = code1 `snocOL`
1873 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1875 CMP L (OpReg src2) (OpReg tmp1)
1877 returnNat (CondCode False cond code__2)
1880 condFltCode cond x y
1881 = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT]))
1882 getRegister x `thenNat` \ register1 ->
1883 getRegister y `thenNat` \ register2 ->
1884 getNewRegNCG (registerRep register1)
1886 getNewRegNCG (registerRep register2)
1888 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1890 code1 = registerCode register1 tmp1
1891 src1 = registerName register1 tmp1
1893 code2 = registerCode register2 tmp2
1894 src2 = registerName register2 tmp2
1896 code__2 | isAny register1
1897 = code1 `appOL` -- result in tmp1
1903 GMOV src1 tmp1 `appOL`
1907 -- The GCMP insn does the test and sets the zero flag if comparable
1908 -- and true. Hence we always supply EQQ as the condition to test.
1909 returnNat (CondCode True EQQ code__2)
1911 #endif {- i386_TARGET_ARCH -}
1913 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1915 #if sparc_TARGET_ARCH
1917 condIntCode cond x (StInt y)
1919 = getRegister x `thenNat` \ register ->
1920 getNewRegNCG IntRep `thenNat` \ tmp ->
1922 code = registerCode register tmp
1923 src1 = registerName register tmp
1924 src2 = ImmInt (fromInteger y)
1925 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1927 returnNat (CondCode False cond code__2)
1929 condIntCode cond x y
1930 = getRegister x `thenNat` \ register1 ->
1931 getRegister y `thenNat` \ register2 ->
1932 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1933 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1935 code1 = registerCode register1 tmp1
1936 src1 = registerName register1 tmp1
1937 code2 = registerCode register2 tmp2
1938 src2 = registerName register2 tmp2
1939 code__2 = code1 `appOL` code2 `snocOL`
1940 SUB False True src1 (RIReg src2) g0
1942 returnNat (CondCode False cond code__2)
1945 condFltCode cond x y
1946 = getRegister x `thenNat` \ register1 ->
1947 getRegister y `thenNat` \ register2 ->
1948 getNewRegNCG (registerRep register1)
1950 getNewRegNCG (registerRep register2)
1952 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1954 promote x = FxTOy F DF x tmp
1956 pk1 = registerRep register1
1957 code1 = registerCode register1 tmp1
1958 src1 = registerName register1 tmp1
1960 pk2 = registerRep register2
1961 code2 = registerCode register2 tmp2
1962 src2 = registerName register2 tmp2
1966 code1 `appOL` code2 `snocOL`
1967 FCMP True (primRepToSize pk1) src1 src2
1968 else if pk1 == FloatRep then
1969 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1970 FCMP True DF tmp src2
1972 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1973 FCMP True DF src1 tmp
1975 returnNat (CondCode True cond code__2)
1977 #endif {- sparc_TARGET_ARCH -}
1979 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1982 %************************************************************************
1984 \subsection{Generating assignments}
1986 %************************************************************************
1988 Assignments are really at the heart of the whole code generation
1989 business. Almost all top-level nodes of any real importance are
1990 assignments, which correspond to loads, stores, or register transfers.
1991 If we're really lucky, some of the register transfers will go away,
1992 because we can use the destination register to complete the code
1993 generation for the right hand side. This only fails when the right
1994 hand side is forced into a fixed register (e.g. the result of a call).
1997 assignMem_IntCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
1998 assignReg_IntCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
2000 assignMem_FltCode :: PrimRep -> StixExpr -> StixExpr -> NatM InstrBlock
2001 assignReg_FltCode :: PrimRep -> StixReg -> StixExpr -> NatM InstrBlock
2003 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2005 #if alpha_TARGET_ARCH
2007 assignIntCode pk (StInd _ dst) src
2008 = getNewRegNCG IntRep `thenNat` \ tmp ->
2009 getAmode dst `thenNat` \ amode ->
2010 getRegister src `thenNat` \ register ->
2012 code1 = amodeCode amode []
2013 dst__2 = amodeAddr amode
2014 code2 = registerCode register tmp []
2015 src__2 = registerName register tmp
2016 sz = primRepToSize pk
2017 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2021 assignIntCode pk dst src
2022 = getRegister dst `thenNat` \ register1 ->
2023 getRegister src `thenNat` \ register2 ->
2025 dst__2 = registerName register1 zeroh
2026 code = registerCode register2 dst__2
2027 src__2 = registerName register2 dst__2
2028 code__2 = if isFixed register2
2029 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
2034 #endif {- alpha_TARGET_ARCH -}
2036 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2038 #if i386_TARGET_ARCH
2040 -- non-FP assignment to memory
2041 assignMem_IntCode pk addr src
2042 = getAmode addr `thenNat` \ amode ->
2043 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
2044 getNewRegNCG PtrRep `thenNat` \ tmp ->
2046 -- In general, if the address computation for dst may require
2047 -- some insns preceding the addressing mode itself. So there's
2048 -- no guarantee that the code for dst and the code for src won't
2049 -- write the same register. This means either the address or
2050 -- the value needs to be copied into a temporary. We detect the
2051 -- common case where the amode has no code, and elide the copy.
2052 codea = amodeCode amode
2053 dst__a = amodeAddr amode
2055 code | isNilOL codea
2057 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
2060 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
2062 MOV (primRepToSize pk) opsrc
2063 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
2069 -> NatM (InstrBlock,Operand) -- code, operator
2072 | Just x <- maybeImm op
2073 = returnNat (nilOL, OpImm x)
2076 = getRegister op `thenNat` \ register ->
2077 getNewRegNCG (registerRep register)
2079 let code = registerCode register tmp
2080 reg = registerName register tmp
2082 returnNat (code, OpReg reg)
2084 -- Assign; dst is a reg, rhs is mem
2085 assignReg_IntCode pk reg (StInd pks src)
2086 = getNewRegNCG PtrRep `thenNat` \ tmp ->
2087 getAmode src `thenNat` \ amode ->
2088 getRegisterReg reg `thenNat` \ reg_dst ->
2090 c_addr = amodeCode amode
2091 am_addr = amodeAddr amode
2092 r_dst = registerName reg_dst tmp
2093 szs = primRepToSize pks
2102 code = c_addr `snocOL`
2103 opc (OpAddr am_addr) (OpReg r_dst)
2107 -- dst is a reg, but src could be anything
2108 assignReg_IntCode pk reg src
2109 = getRegisterReg reg `thenNat` \ registerd ->
2110 getRegister src `thenNat` \ registers ->
2111 getNewRegNCG IntRep `thenNat` \ tmp ->
2113 r_dst = registerName registerd tmp
2114 r_src = registerName registers r_dst
2115 c_src = registerCode registers r_dst
2117 code = c_src `snocOL`
2118 MOV L (OpReg r_src) (OpReg r_dst)
2122 #endif {- i386_TARGET_ARCH -}
2124 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2126 #if sparc_TARGET_ARCH
2128 assignMem_IntCode pk addr src
2129 = getNewRegNCG IntRep `thenNat` \ tmp ->
2130 getAmode addr `thenNat` \ amode ->
2131 getRegister src `thenNat` \ register ->
2133 code1 = amodeCode amode
2134 dst__2 = amodeAddr amode
2135 code2 = registerCode register tmp
2136 src__2 = registerName register tmp
2137 sz = primRepToSize pk
2138 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
2142 assignReg_IntCode pk reg src
2143 = getRegister src `thenNat` \ register2 ->
2144 getRegisterReg reg `thenNat` \ register1 ->
2146 dst__2 = registerName register1 g0
2147 code = registerCode register2 dst__2
2148 src__2 = registerName register2 dst__2
2149 code__2 = if isFixed register2
2150 then code `snocOL` OR False g0 (RIReg src__2) dst__2
2155 #endif {- sparc_TARGET_ARCH -}
2157 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2160 % --------------------------------
2161 Floating-point assignments:
2162 % --------------------------------
2165 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2166 #if alpha_TARGET_ARCH
2168 assignFltCode pk (StInd _ dst) src
2169 = getNewRegNCG pk `thenNat` \ tmp ->
2170 getAmode dst `thenNat` \ amode ->
2171 getRegister src `thenNat` \ register ->
2173 code1 = amodeCode amode []
2174 dst__2 = amodeAddr amode
2175 code2 = registerCode register tmp []
2176 src__2 = registerName register tmp
2177 sz = primRepToSize pk
2178 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2182 assignFltCode pk dst src
2183 = getRegister dst `thenNat` \ register1 ->
2184 getRegister src `thenNat` \ register2 ->
2186 dst__2 = registerName register1 zeroh
2187 code = registerCode register2 dst__2
2188 src__2 = registerName register2 dst__2
2189 code__2 = if isFixed register2
2190 then code . mkSeqInstr (FMOV src__2 dst__2)
2195 #endif {- alpha_TARGET_ARCH -}
2197 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2199 #if i386_TARGET_ARCH
2201 -- Floating point assignment to memory
2202 assignMem_FltCode pk addr src
2203 = getRegister src `thenNat` \ reg_src ->
2204 getRegister addr `thenNat` \ reg_addr ->
2205 getNewRegNCG pk `thenNat` \ tmp_src ->
2206 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
2207 let r_src = registerName reg_src tmp_src
2208 c_src = registerCode reg_src tmp_src
2209 r_addr = registerName reg_addr tmp_addr
2210 c_addr = registerCode reg_addr tmp_addr
2211 sz = primRepToSize pk
2213 code = c_src `appOL`
2214 -- no need to preserve r_src across the addr computation,
2215 -- since r_src must be a float reg
2216 -- whilst r_addr is an int reg
2219 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
2223 -- Floating point assignment to a register/temporary
2224 assignReg_FltCode pk reg src
2225 = getRegisterReg reg `thenNat` \ reg_dst ->
2226 getRegister src `thenNat` \ reg_src ->
2227 getNewRegNCG pk `thenNat` \ tmp ->
2229 r_dst = registerName reg_dst tmp
2230 r_src = registerName reg_src r_dst
2231 c_src = registerCode reg_src r_dst
2233 code = if isFixed reg_src
2234 then c_src `snocOL` GMOV r_src r_dst
2240 #endif {- i386_TARGET_ARCH -}
2242 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2244 #if sparc_TARGET_ARCH
2246 -- Floating point assignment to memory
2247 assignMem_FltCode pk addr src
2248 = getNewRegNCG pk `thenNat` \ tmp1 ->
2249 getAmode addr `thenNat` \ amode ->
2250 getRegister src `thenNat` \ register ->
2252 sz = primRepToSize pk
2253 dst__2 = amodeAddr amode
2255 code1 = amodeCode amode
2256 code2 = registerCode register tmp1
2258 src__2 = registerName register tmp1
2259 pk__2 = registerRep register
2260 sz__2 = primRepToSize pk__2
2262 code__2 = code1 `appOL` code2 `appOL`
2264 then unitOL (ST sz src__2 dst__2)
2265 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
2269 -- Floating point assignment to a register/temporary
2270 -- Why is this so bizarrely ugly?
2271 assignReg_FltCode pk reg src
2272 = getRegisterReg reg `thenNat` \ register1 ->
2273 getRegister src `thenNat` \ register2 ->
2275 pk__2 = registerRep register2
2276 sz__2 = primRepToSize pk__2
2278 getNewRegNCG pk__2 `thenNat` \ tmp ->
2280 sz = primRepToSize pk
2281 dst__2 = registerName register1 g0 -- must be Fixed
2282 reg__2 = if pk /= pk__2 then tmp else dst__2
2283 code = registerCode register2 reg__2
2284 src__2 = registerName register2 reg__2
2287 code `snocOL` FxTOy sz__2 sz src__2 dst__2
2288 else if isFixed register2 then
2289 code `snocOL` FMOV sz src__2 dst__2
2295 #endif {- sparc_TARGET_ARCH -}
2297 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2300 %************************************************************************
2302 \subsection{Generating an unconditional branch}
2304 %************************************************************************
2306 We accept two types of targets: an immediate CLabel or a tree that
2307 gets evaluated into a register. Any CLabels which are AsmTemporaries
2308 are assumed to be in the local block of code, close enough for a
2309 branch instruction. Other CLabels are assumed to be far away.
2311 (If applicable) Do not fill the delay slots here; you will confuse the
2315 genJump :: DestInfo -> StixExpr{-the branch target-} -> NatM InstrBlock
2317 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2319 #if alpha_TARGET_ARCH
2321 genJump (StCLbl lbl)
2322 | isAsmTemp lbl = returnInstr (BR target)
2323 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2325 target = ImmCLbl lbl
2328 = getRegister tree `thenNat` \ register ->
2329 getNewRegNCG PtrRep `thenNat` \ tmp ->
2331 dst = registerName register pv
2332 code = registerCode register pv
2333 target = registerName register pv
2335 if isFixed register then
2336 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2338 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2340 #endif {- alpha_TARGET_ARCH -}
2342 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2344 #if i386_TARGET_ARCH
2346 genJump dsts (StInd pk mem)
2347 = getAmode mem `thenNat` \ amode ->
2349 code = amodeCode amode
2350 target = amodeAddr amode
2352 returnNat (code `snocOL` JMP dsts (OpAddr target))
2356 = returnNat (unitOL (JMP dsts (OpImm target)))
2359 = getRegister tree `thenNat` \ register ->
2360 getNewRegNCG PtrRep `thenNat` \ tmp ->
2362 code = registerCode register tmp
2363 target = registerName register tmp
2365 returnNat (code `snocOL` JMP dsts (OpReg target))
2368 target = case imm of Just x -> x
2370 #endif {- i386_TARGET_ARCH -}
2372 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2374 #if sparc_TARGET_ARCH
2376 genJump dsts (StCLbl lbl)
2377 | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
2378 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2379 | otherwise = returnNat (toOL [CALL (Left target) 0 True, NOP])
2381 target = ImmCLbl lbl
2384 = getRegister tree `thenNat` \ register ->
2385 getNewRegNCG PtrRep `thenNat` \ tmp ->
2387 code = registerCode register tmp
2388 target = registerName register tmp
2390 returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
2392 #endif {- sparc_TARGET_ARCH -}
2394 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2397 %************************************************************************
2399 \subsection{Conditional jumps}
2401 %************************************************************************
2403 Conditional jumps are always to local labels, so we can use branch
2404 instructions. We peek at the arguments to decide what kind of
2407 ALPHA: For comparisons with 0, we're laughing, because we can just do
2408 the desired conditional branch.
2410 I386: First, we have to ensure that the condition
2411 codes are set according to the supplied comparison operation.
2413 SPARC: First, we have to ensure that the condition codes are set
2414 according to the supplied comparison operation. We generate slightly
2415 different code for floating point comparisons, because a floating
2416 point operation cannot directly precede a @BF@. We assume the worst
2417 and fill that slot with a @NOP@.
2419 SPARC: Do not fill the delay slots here; you will confuse the register
2424 :: CLabel -- the branch target
2425 -> StixExpr -- the condition on which to branch
2428 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2430 #if alpha_TARGET_ARCH
2432 genCondJump lbl (StPrim op [x, StInt 0])
2433 = getRegister x `thenNat` \ register ->
2434 getNewRegNCG (registerRep register)
2437 code = registerCode register tmp
2438 value = registerName register tmp
2439 pk = registerRep register
2440 target = ImmCLbl lbl
2442 returnSeq code [BI (cmpOp op) value target]
2444 cmpOp CharGtOp = GTT
2446 cmpOp CharEqOp = EQQ
2448 cmpOp CharLtOp = LTT
2457 cmpOp WordGeOp = ALWAYS
2458 cmpOp WordEqOp = EQQ
2460 cmpOp WordLtOp = NEVER
2461 cmpOp WordLeOp = EQQ
2463 cmpOp AddrGeOp = ALWAYS
2464 cmpOp AddrEqOp = EQQ
2466 cmpOp AddrLtOp = NEVER
2467 cmpOp AddrLeOp = EQQ
2469 genCondJump lbl (StPrim op [x, StDouble 0.0])
2470 = getRegister x `thenNat` \ register ->
2471 getNewRegNCG (registerRep register)
2474 code = registerCode register tmp
2475 value = registerName register tmp
2476 pk = registerRep register
2477 target = ImmCLbl lbl
2479 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2481 cmpOp FloatGtOp = GTT
2482 cmpOp FloatGeOp = GE
2483 cmpOp FloatEqOp = EQQ
2484 cmpOp FloatNeOp = NE
2485 cmpOp FloatLtOp = LTT
2486 cmpOp FloatLeOp = LE
2487 cmpOp DoubleGtOp = GTT
2488 cmpOp DoubleGeOp = GE
2489 cmpOp DoubleEqOp = EQQ
2490 cmpOp DoubleNeOp = NE
2491 cmpOp DoubleLtOp = LTT
2492 cmpOp DoubleLeOp = LE
2494 genCondJump lbl (StPrim op [x, y])
2496 = trivialFCode pr instr x y `thenNat` \ register ->
2497 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2499 code = registerCode register tmp
2500 result = registerName register tmp
2501 target = ImmCLbl lbl
2503 returnNat (code . mkSeqInstr (BF cond result target))
2505 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2507 fltCmpOp op = case op of
2521 (instr, cond) = case op of
2522 FloatGtOp -> (FCMP TF LE, EQQ)
2523 FloatGeOp -> (FCMP TF LTT, EQQ)
2524 FloatEqOp -> (FCMP TF EQQ, NE)
2525 FloatNeOp -> (FCMP TF EQQ, EQQ)
2526 FloatLtOp -> (FCMP TF LTT, NE)
2527 FloatLeOp -> (FCMP TF LE, NE)
2528 DoubleGtOp -> (FCMP TF LE, EQQ)
2529 DoubleGeOp -> (FCMP TF LTT, EQQ)
2530 DoubleEqOp -> (FCMP TF EQQ, NE)
2531 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2532 DoubleLtOp -> (FCMP TF LTT, NE)
2533 DoubleLeOp -> (FCMP TF LE, NE)
2535 genCondJump lbl (StPrim op [x, y])
2536 = trivialCode instr x y `thenNat` \ register ->
2537 getNewRegNCG IntRep `thenNat` \ tmp ->
2539 code = registerCode register tmp
2540 result = registerName register tmp
2541 target = ImmCLbl lbl
2543 returnNat (code . mkSeqInstr (BI cond result target))
2545 (instr, cond) = case op of
2546 CharGtOp -> (CMP LE, EQQ)
2547 CharGeOp -> (CMP LTT, EQQ)
2548 CharEqOp -> (CMP EQQ, NE)
2549 CharNeOp -> (CMP EQQ, EQQ)
2550 CharLtOp -> (CMP LTT, NE)
2551 CharLeOp -> (CMP LE, NE)
2552 IntGtOp -> (CMP LE, EQQ)
2553 IntGeOp -> (CMP LTT, EQQ)
2554 IntEqOp -> (CMP EQQ, NE)
2555 IntNeOp -> (CMP EQQ, EQQ)
2556 IntLtOp -> (CMP LTT, NE)
2557 IntLeOp -> (CMP LE, NE)
2558 WordGtOp -> (CMP ULE, EQQ)
2559 WordGeOp -> (CMP ULT, EQQ)
2560 WordEqOp -> (CMP EQQ, NE)
2561 WordNeOp -> (CMP EQQ, EQQ)
2562 WordLtOp -> (CMP ULT, NE)
2563 WordLeOp -> (CMP ULE, NE)
2564 AddrGtOp -> (CMP ULE, EQQ)
2565 AddrGeOp -> (CMP ULT, EQQ)
2566 AddrEqOp -> (CMP EQQ, NE)
2567 AddrNeOp -> (CMP EQQ, EQQ)
2568 AddrLtOp -> (CMP ULT, NE)
2569 AddrLeOp -> (CMP ULE, NE)
2571 #endif {- alpha_TARGET_ARCH -}
2573 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2575 #if i386_TARGET_ARCH
2577 genCondJump lbl bool
2578 = getCondCode bool `thenNat` \ condition ->
2580 code = condCode condition
2581 cond = condName condition
2583 returnNat (code `snocOL` JXX cond lbl)
2585 #endif {- i386_TARGET_ARCH -}
2587 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2589 #if sparc_TARGET_ARCH
2591 genCondJump lbl bool
2592 = getCondCode bool `thenNat` \ condition ->
2594 code = condCode condition
2595 cond = condName condition
2596 target = ImmCLbl lbl
2601 if condFloat condition
2602 then [NOP, BF cond False target, NOP]
2603 else [BI cond False target, NOP]
2607 #endif {- sparc_TARGET_ARCH -}
2609 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2612 %************************************************************************
2614 \subsection{Generating C calls}
2616 %************************************************************************
2618 Now the biggest nightmare---calls. Most of the nastiness is buried in
2619 @get_arg@, which moves the arguments to the correct registers/stack
2620 locations. Apart from that, the code is easy.
2622 (If applicable) Do not fill the delay slots here; you will confuse the
2627 :: (Either FAST_STRING StixExpr) -- function to call
2629 -> PrimRep -- type of the result
2630 -> [StixExpr] -- arguments (of mixed type)
2633 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2635 #if alpha_TARGET_ARCH
2637 genCCall fn cconv kind args
2638 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2639 `thenNat` \ ((unused,_), argCode) ->
2641 nRegs = length allArgRegs - length unused
2642 code = asmSeqThen (map ($ []) argCode)
2645 LDA pv (AddrImm (ImmLab (ptext fn))),
2646 JSR ra (AddrReg pv) nRegs,
2647 LDGP gp (AddrReg ra)]
2649 ------------------------
2650 {- Try to get a value into a specific register (or registers) for
2651 a call. The first 6 arguments go into the appropriate
2652 argument register (separate registers for integer and floating
2653 point arguments, but used in lock-step), and the remaining
2654 arguments are dumped to the stack, beginning at 0(sp). Our
2655 first argument is a pair of the list of remaining argument
2656 registers to be assigned for this call and the next stack
2657 offset to use for overflowing arguments. This way,
2658 @get_Arg@ can be applied to all of a call's arguments using
2662 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2663 -> StixTree -- Current argument
2664 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2666 -- We have to use up all of our argument registers first...
2668 get_arg ((iDst,fDst):dsts, offset) arg
2669 = getRegister arg `thenNat` \ register ->
2671 reg = if isFloatingRep pk then fDst else iDst
2672 code = registerCode register reg
2673 src = registerName register reg
2674 pk = registerRep register
2677 if isFloatingRep pk then
2678 ((dsts, offset), if isFixed register then
2679 code . mkSeqInstr (FMOV src fDst)
2682 ((dsts, offset), if isFixed register then
2683 code . mkSeqInstr (OR src (RIReg src) iDst)
2686 -- Once we have run out of argument registers, we move to the
2689 get_arg ([], offset) arg
2690 = getRegister arg `thenNat` \ register ->
2691 getNewRegNCG (registerRep register)
2694 code = registerCode register tmp
2695 src = registerName register tmp
2696 pk = registerRep register
2697 sz = primRepToSize pk
2699 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2701 #endif {- alpha_TARGET_ARCH -}
2703 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2705 #if i386_TARGET_ARCH
2707 genCCall fn cconv ret_rep args
2709 (reverse args) `thenNat` \ sizes_n_codes ->
2710 getDeltaNat `thenNat` \ delta ->
2711 let (sizes, push_codes) = unzip sizes_n_codes
2712 tot_arg_size = sum sizes
2714 -- deal with static vs dynamic call targets
2717 -> returnNat (unitOL (CALL (Left (fn__2 tot_arg_size))))
2719 -> get_op dyn `thenNat` \ (dyn_c, dyn_r, dyn_rep) ->
2720 ASSERT(case dyn_rep of { L -> True; _ -> False})
2721 returnNat (dyn_c `snocOL` CALL (Right dyn_r))
2723 `thenNat` \ callinsns ->
2724 let push_code = concatOL push_codes
2725 call = callinsns `appOL`
2727 -- Deallocate parameters after call for ccall;
2728 -- but not for stdcall (callee does it)
2729 (if cconv == StdCallConv then [] else
2730 [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2732 [DELTA (delta + tot_arg_size)]
2735 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2736 returnNat (push_code `appOL` call)
2739 -- function names that begin with '.' are assumed to be special
2740 -- internally generated names like '.mul,' which don't get an
2741 -- underscore prefix
2742 -- ToDo:needed (WDP 96/03) ???
2743 fn_u = _UNPK_ (unLeft fn)
2746 = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
2747 | otherwise -- General case
2748 = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
2750 stdcallsize tot_arg_size
2751 | cconv == StdCallConv = '@':show tot_arg_size
2759 push_arg :: StixExpr{-current argument-}
2760 -> NatM (Int, InstrBlock) -- argsz, code
2763 | is64BitRep arg_rep
2764 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2765 getDeltaNat `thenNat` \ delta ->
2766 setDeltaNat (delta - 8) `thenNat` \ _ ->
2767 let r_lo = VirtualRegI vr_lo
2768 r_hi = getHiVRegFromLo r_lo
2771 toOL [PUSH L (OpReg r_hi), DELTA (delta - 4),
2772 PUSH L (OpReg r_lo), DELTA (delta - 8)]
2775 = get_op arg `thenNat` \ (code, reg, sz) ->
2776 getDeltaNat `thenNat` \ delta ->
2777 arg_size sz `bind` \ size ->
2778 setDeltaNat (delta-size) `thenNat` \ _ ->
2779 if (case sz of DF -> True; F -> True; _ -> False)
2780 then returnNat (size,
2782 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2784 GST sz reg (AddrBaseIndex (Just esp)
2788 else returnNat (size,
2790 PUSH L (OpReg reg) `snocOL`
2794 arg_rep = repOfStixExpr arg
2799 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2802 = getRegister op `thenNat` \ register ->
2803 getNewRegNCG (registerRep register)
2806 code = registerCode register tmp
2807 reg = registerName register tmp
2808 pk = registerRep register
2809 sz = primRepToSize pk
2811 returnNat (code, reg, sz)
2813 #endif {- i386_TARGET_ARCH -}
2815 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2817 #if sparc_TARGET_ARCH
2819 The SPARC calling convention is an absolute
2820 nightmare. The first 6x32 bits of arguments are mapped into
2821 %o0 through %o5, and the remaining arguments are dumped to the
2822 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
2824 If we have to put args on the stack, move %o6==%sp down by
2825 the number of words to go on the stack, to ensure there's enough space.
2827 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
2828 16 words above the stack pointer is a word for the address of
2829 a structure return value. I use this as a temporary location
2830 for moving values from float to int regs. Certainly it isn't
2831 safe to put anything in the 16 words starting at %sp, since
2832 this area can get trashed at any time due to window overflows
2833 caused by signal handlers.
2835 A final complication (if the above isn't enough) is that
2836 we can't blithely calculate the arguments one by one into
2837 %o0 .. %o5. Consider the following nested calls:
2841 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
2842 the inner call will itself use %o0, which trashes the value put there
2843 in preparation for the outer call. Upshot: we need to calculate the
2844 args into temporary regs, and move those to arg regs or onto the
2845 stack only immediately prior to the call proper. Sigh.
2848 genCCall fn cconv kind args
2849 = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
2851 (argcodes, vregss) = unzip argcode_and_vregs
2852 n_argRegs = length allArgRegs
2853 n_argRegs_used = min (length vregs) n_argRegs
2854 vregs = concat vregss
2856 -- deal with static vs dynamic call targets
2859 -> returnNat (unitOL (CALL (Left fn__2) n_argRegs_used False))
2861 -> arg_to_int_vregs dyn `thenNat` \ (dyn_c, [dyn_r]) ->
2862 returnNat (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
2864 `thenNat` \ callinsns ->
2866 argcode = concatOL argcodes
2867 (move_sp_down, move_sp_up)
2868 = let nn = length vregs - n_argRegs
2869 + 1 -- (for the road)
2872 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
2874 = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
2876 returnNat (argcode `appOL`
2877 move_sp_down `appOL`
2878 transfer_code `appOL`
2883 -- function names that begin with '.' are assumed to be special
2884 -- internally generated names like '.mul,' which don't get an
2885 -- underscore prefix
2886 -- ToDo:needed (WDP 96/03) ???
2887 fn_static = unLeft fn
2888 fn__2 = case (_HEAD_ fn_static) of
2889 '.' -> ImmLit (ptext fn_static)
2890 _ -> ImmLab False (ptext fn_static)
2892 -- move args from the integer vregs into which they have been
2893 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
2894 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
2896 move_final [] _ offset -- all args done
2899 move_final (v:vs) [] offset -- out of aregs; move to stack
2900 = ST W v (spRel offset)
2901 : move_final vs [] (offset+1)
2903 move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
2904 = OR False g0 (RIReg v) a
2905 : move_final vs az offset
2907 -- generate code to calculate an argument, and move it into one
2908 -- or two integer vregs.
2909 arg_to_int_vregs :: StixExpr -> NatM (OrdList Instr, [Reg])
2910 arg_to_int_vregs arg
2911 | is64BitRep (repOfStixExpr arg)
2912 = iselExpr64 arg `thenNat` \ (ChildCode64 code vr_lo) ->
2913 let r_lo = VirtualRegI vr_lo
2914 r_hi = getHiVRegFromLo r_lo
2915 in returnNat (code, [r_hi, r_lo])
2917 = getRegister arg `thenNat` \ register ->
2918 getNewRegNCG (registerRep register) `thenNat` \ tmp ->
2919 let code = registerCode register tmp
2920 src = registerName register tmp
2921 pk = registerRep register
2923 -- the value is in src. Get it into 1 or 2 int vregs.
2926 getNewRegNCG WordRep `thenNat` \ v1 ->
2927 getNewRegNCG WordRep `thenNat` \ v2 ->
2930 FMOV DF src f0 `snocOL`
2931 ST F f0 (spRel 16) `snocOL`
2932 LD W (spRel 16) v1 `snocOL`
2933 ST F (fPair f0) (spRel 16) `snocOL`
2939 getNewRegNCG WordRep `thenNat` \ v1 ->
2942 ST F src (spRel 16) `snocOL`
2948 getNewRegNCG WordRep `thenNat` \ v1 ->
2950 code `snocOL` OR False g0 (RIReg src) v1
2954 #endif {- sparc_TARGET_ARCH -}
2956 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2959 %************************************************************************
2961 \subsection{Support bits}
2963 %************************************************************************
2965 %************************************************************************
2967 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2969 %************************************************************************
2971 Turn those condition codes into integers now (when they appear on
2972 the right hand side of an assignment).
2974 (If applicable) Do not fill the delay slots here; you will confuse the
2978 condIntReg, condFltReg :: Cond -> StixExpr -> StixExpr -> NatM Register
2980 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2982 #if alpha_TARGET_ARCH
2983 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2984 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2985 #endif {- alpha_TARGET_ARCH -}
2987 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2989 #if i386_TARGET_ARCH
2992 = condIntCode cond x y `thenNat` \ condition ->
2993 getNewRegNCG IntRep `thenNat` \ tmp ->
2995 code = condCode condition
2996 cond = condName condition
2997 code__2 dst = code `appOL` toOL [
2998 SETCC cond (OpReg tmp),
2999 AND L (OpImm (ImmInt 1)) (OpReg tmp),
3000 MOV L (OpReg tmp) (OpReg dst)]
3002 returnNat (Any IntRep code__2)
3005 = getNatLabelNCG `thenNat` \ lbl1 ->
3006 getNatLabelNCG `thenNat` \ lbl2 ->
3007 condFltCode cond x y `thenNat` \ condition ->
3009 code = condCode condition
3010 cond = condName condition
3011 code__2 dst = code `appOL` toOL [
3013 MOV L (OpImm (ImmInt 0)) (OpReg dst),
3016 MOV L (OpImm (ImmInt 1)) (OpReg dst),
3019 returnNat (Any IntRep code__2)
3021 #endif {- i386_TARGET_ARCH -}
3023 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3025 #if sparc_TARGET_ARCH
3027 condIntReg EQQ x (StInt 0)
3028 = getRegister x `thenNat` \ register ->
3029 getNewRegNCG IntRep `thenNat` \ tmp ->
3031 code = registerCode register tmp
3032 src = registerName register tmp
3033 code__2 dst = code `appOL` toOL [
3034 SUB False True g0 (RIReg src) g0,
3035 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3037 returnNat (Any IntRep code__2)
3040 = getRegister x `thenNat` \ register1 ->
3041 getRegister y `thenNat` \ register2 ->
3042 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3043 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3045 code1 = registerCode register1 tmp1
3046 src1 = registerName register1 tmp1
3047 code2 = registerCode register2 tmp2
3048 src2 = registerName register2 tmp2
3049 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3050 XOR False src1 (RIReg src2) dst,
3051 SUB False True g0 (RIReg dst) g0,
3052 SUB True False g0 (RIImm (ImmInt (-1))) dst]
3054 returnNat (Any IntRep code__2)
3056 condIntReg NE x (StInt 0)
3057 = getRegister x `thenNat` \ register ->
3058 getNewRegNCG IntRep `thenNat` \ tmp ->
3060 code = registerCode register tmp
3061 src = registerName register tmp
3062 code__2 dst = code `appOL` toOL [
3063 SUB False True g0 (RIReg src) g0,
3064 ADD True False g0 (RIImm (ImmInt 0)) dst]
3066 returnNat (Any IntRep code__2)
3069 = getRegister x `thenNat` \ register1 ->
3070 getRegister y `thenNat` \ register2 ->
3071 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3072 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3074 code1 = registerCode register1 tmp1
3075 src1 = registerName register1 tmp1
3076 code2 = registerCode register2 tmp2
3077 src2 = registerName register2 tmp2
3078 code__2 dst = code1 `appOL` code2 `appOL` toOL [
3079 XOR False src1 (RIReg src2) dst,
3080 SUB False True g0 (RIReg dst) g0,
3081 ADD True False g0 (RIImm (ImmInt 0)) dst]
3083 returnNat (Any IntRep code__2)
3086 = getNatLabelNCG `thenNat` \ lbl1 ->
3087 getNatLabelNCG `thenNat` \ lbl2 ->
3088 condIntCode cond x y `thenNat` \ condition ->
3090 code = condCode condition
3091 cond = condName condition
3092 code__2 dst = code `appOL` toOL [
3093 BI cond False (ImmCLbl lbl1), NOP,
3094 OR False g0 (RIImm (ImmInt 0)) dst,
3095 BI ALWAYS False (ImmCLbl lbl2), NOP,
3097 OR False g0 (RIImm (ImmInt 1)) dst,
3100 returnNat (Any IntRep code__2)
3103 = getNatLabelNCG `thenNat` \ lbl1 ->
3104 getNatLabelNCG `thenNat` \ lbl2 ->
3105 condFltCode cond x y `thenNat` \ condition ->
3107 code = condCode condition
3108 cond = condName condition
3109 code__2 dst = code `appOL` toOL [
3111 BF cond False (ImmCLbl lbl1), NOP,
3112 OR False g0 (RIImm (ImmInt 0)) dst,
3113 BI ALWAYS False (ImmCLbl lbl2), NOP,
3115 OR False g0 (RIImm (ImmInt 1)) dst,
3118 returnNat (Any IntRep code__2)
3120 #endif {- sparc_TARGET_ARCH -}
3122 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3125 %************************************************************************
3127 \subsubsection{@trivial*Code@: deal with trivial instructions}
3129 %************************************************************************
3131 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
3132 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
3133 for constants on the right hand side, because that's where the generic
3134 optimizer will have put them.
3136 Similarly, for unary instructions, we don't have to worry about
3137 matching an StInt as the argument, because genericOpt will already
3138 have handled the constant-folding.
3142 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
3143 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
3144 -> Maybe (Operand -> Operand -> Instr)
3145 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
3147 -> StixExpr -> StixExpr -- the two arguments
3152 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
3153 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
3154 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
3156 -> StixExpr -> StixExpr -- the two arguments
3160 :: IF_ARCH_alpha((RI -> Reg -> Instr)
3161 ,IF_ARCH_i386 ((Operand -> Instr)
3162 ,IF_ARCH_sparc((RI -> Reg -> Instr)
3164 -> StixExpr -- the one argument
3169 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
3170 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
3171 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
3173 -> StixExpr -- the one argument
3176 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3178 #if alpha_TARGET_ARCH
3180 trivialCode instr x (StInt y)
3182 = getRegister x `thenNat` \ register ->
3183 getNewRegNCG IntRep `thenNat` \ tmp ->
3185 code = registerCode register tmp
3186 src1 = registerName register tmp
3187 src2 = ImmInt (fromInteger y)
3188 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
3190 returnNat (Any IntRep code__2)
3192 trivialCode instr x y
3193 = getRegister x `thenNat` \ register1 ->
3194 getRegister y `thenNat` \ register2 ->
3195 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3196 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3198 code1 = registerCode register1 tmp1 []
3199 src1 = registerName register1 tmp1
3200 code2 = registerCode register2 tmp2 []
3201 src2 = registerName register2 tmp2
3202 code__2 dst = asmSeqThen [code1, code2] .
3203 mkSeqInstr (instr src1 (RIReg src2) dst)
3205 returnNat (Any IntRep code__2)
3208 trivialUCode instr x
3209 = getRegister x `thenNat` \ register ->
3210 getNewRegNCG IntRep `thenNat` \ tmp ->
3212 code = registerCode register tmp
3213 src = registerName register tmp
3214 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3216 returnNat (Any IntRep code__2)
3219 trivialFCode _ instr x y
3220 = getRegister x `thenNat` \ register1 ->
3221 getRegister y `thenNat` \ register2 ->
3222 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3223 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3225 code1 = registerCode register1 tmp1
3226 src1 = registerName register1 tmp1
3228 code2 = registerCode register2 tmp2
3229 src2 = registerName register2 tmp2
3231 code__2 dst = asmSeqThen [code1 [], code2 []] .
3232 mkSeqInstr (instr src1 src2 dst)
3234 returnNat (Any DoubleRep code__2)
3236 trivialUFCode _ instr x
3237 = getRegister x `thenNat` \ register ->
3238 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3240 code = registerCode register tmp
3241 src = registerName register tmp
3242 code__2 dst = code . mkSeqInstr (instr src dst)
3244 returnNat (Any DoubleRep code__2)
3246 #endif {- alpha_TARGET_ARCH -}
3248 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3250 #if i386_TARGET_ARCH
3252 The Rules of the Game are:
3254 * You cannot assume anything about the destination register dst;
3255 it may be anything, including a fixed reg.
3257 * You may compute an operand into a fixed reg, but you may not
3258 subsequently change the contents of that fixed reg. If you
3259 want to do so, first copy the value either to a temporary
3260 or into dst. You are free to modify dst even if it happens
3261 to be a fixed reg -- that's not your problem.
3263 * You cannot assume that a fixed reg will stay live over an
3264 arbitrary computation. The same applies to the dst reg.
3266 * Temporary regs obtained from getNewRegNCG are distinct from
3267 each other and from all other regs, and stay live over
3268 arbitrary computations.
3272 trivialCode instr maybe_revinstr a b
3275 = getRegister a `thenNat` \ rega ->
3278 then registerCode rega dst `bind` \ code_a ->
3280 instr (OpImm imm_b) (OpReg dst)
3281 else registerCodeF rega `bind` \ code_a ->
3282 registerNameF rega `bind` \ r_a ->
3284 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3285 instr (OpImm imm_b) (OpReg dst)
3287 returnNat (Any IntRep mkcode)
3290 = getRegister b `thenNat` \ regb ->
3291 getNewRegNCG IntRep `thenNat` \ tmp ->
3292 let revinstr_avail = maybeToBool maybe_revinstr
3293 revinstr = case maybe_revinstr of Just ri -> ri
3297 then registerCode regb dst `bind` \ code_b ->
3299 revinstr (OpImm imm_a) (OpReg dst)
3300 else registerCodeF regb `bind` \ code_b ->
3301 registerNameF regb `bind` \ r_b ->
3303 MOV L (OpReg r_b) (OpReg dst) `snocOL`
3304 revinstr (OpImm imm_a) (OpReg dst)
3308 then registerCode regb tmp `bind` \ code_b ->
3310 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3311 instr (OpReg tmp) (OpReg dst)
3312 else registerCodeF regb `bind` \ code_b ->
3313 registerNameF regb `bind` \ r_b ->
3315 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
3316 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3317 instr (OpReg tmp) (OpReg dst)
3319 returnNat (Any IntRep mkcode)
3322 = getRegister a `thenNat` \ rega ->
3323 getRegister b `thenNat` \ regb ->
3324 getNewRegNCG IntRep `thenNat` \ tmp ->
3326 = case (isAny rega, isAny regb) of
3328 -> registerCode regb tmp `bind` \ code_b ->
3329 registerCode rega dst `bind` \ code_a ->
3332 instr (OpReg tmp) (OpReg dst)
3334 -> registerCode rega tmp `bind` \ code_a ->
3335 registerCodeF regb `bind` \ code_b ->
3336 registerNameF regb `bind` \ r_b ->
3339 instr (OpReg r_b) (OpReg tmp) `snocOL`
3340 MOV L (OpReg tmp) (OpReg dst)
3342 -> registerCode regb tmp `bind` \ code_b ->
3343 registerCodeF rega `bind` \ code_a ->
3344 registerNameF rega `bind` \ r_a ->
3347 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3348 instr (OpReg tmp) (OpReg dst)
3350 -> registerCodeF rega `bind` \ code_a ->
3351 registerNameF rega `bind` \ r_a ->
3352 registerCodeF regb `bind` \ code_b ->
3353 registerNameF regb `bind` \ r_b ->
3355 MOV L (OpReg r_a) (OpReg tmp) `appOL`
3357 instr (OpReg r_b) (OpReg tmp) `snocOL`
3358 MOV L (OpReg tmp) (OpReg dst)
3360 returnNat (Any IntRep mkcode)
3363 maybe_imm_a = maybeImm a
3364 is_imm_a = maybeToBool maybe_imm_a
3365 imm_a = case maybe_imm_a of Just imm -> imm
3367 maybe_imm_b = maybeImm b
3368 is_imm_b = maybeToBool maybe_imm_b
3369 imm_b = case maybe_imm_b of Just imm -> imm
3373 trivialUCode instr x
3374 = getRegister x `thenNat` \ register ->
3376 code__2 dst = let code = registerCode register dst
3377 src = registerName register dst
3379 if isFixed register && dst /= src
3380 then toOL [MOV L (OpReg src) (OpReg dst),
3382 else unitOL (instr (OpReg src))
3384 returnNat (Any IntRep code__2)
3387 trivialFCode pk instr x y
3388 = getRegister x `thenNat` \ register1 ->
3389 getRegister y `thenNat` \ register2 ->
3390 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3391 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3393 code1 = registerCode register1 tmp1
3394 src1 = registerName register1 tmp1
3396 code2 = registerCode register2 tmp2
3397 src2 = registerName register2 tmp2
3400 -- treat the common case specially: both operands in
3402 | isAny register1 && isAny register2
3405 instr (primRepToSize pk) src1 src2 dst
3407 -- be paranoid (and inefficient)
3409 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3411 instr (primRepToSize pk) tmp1 src2 dst
3413 returnNat (Any pk code__2)
3417 trivialUFCode pk instr x
3418 = getRegister x `thenNat` \ register ->
3419 getNewRegNCG pk `thenNat` \ tmp ->
3421 code = registerCode register tmp
3422 src = registerName register tmp
3423 code__2 dst = code `snocOL` instr src dst
3425 returnNat (Any pk code__2)
3427 #endif {- i386_TARGET_ARCH -}
3429 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3431 #if sparc_TARGET_ARCH
3433 trivialCode instr x (StInt y)
3435 = getRegister x `thenNat` \ register ->
3436 getNewRegNCG IntRep `thenNat` \ tmp ->
3438 code = registerCode register tmp
3439 src1 = registerName register tmp
3440 src2 = ImmInt (fromInteger y)
3441 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3443 returnNat (Any IntRep code__2)
3445 trivialCode instr x y
3446 = getRegister x `thenNat` \ register1 ->
3447 getRegister y `thenNat` \ register2 ->
3448 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3449 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3451 code1 = registerCode register1 tmp1
3452 src1 = registerName register1 tmp1
3453 code2 = registerCode register2 tmp2
3454 src2 = registerName register2 tmp2
3455 code__2 dst = code1 `appOL` code2 `snocOL`
3456 instr src1 (RIReg src2) dst
3458 returnNat (Any IntRep code__2)
3461 trivialFCode pk instr x y
3462 = getRegister x `thenNat` \ register1 ->
3463 getRegister y `thenNat` \ register2 ->
3464 getNewRegNCG (registerRep register1)
3466 getNewRegNCG (registerRep register2)
3468 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3470 promote x = FxTOy F DF x tmp
3472 pk1 = registerRep register1
3473 code1 = registerCode register1 tmp1
3474 src1 = registerName register1 tmp1
3476 pk2 = registerRep register2
3477 code2 = registerCode register2 tmp2
3478 src2 = registerName register2 tmp2
3482 code1 `appOL` code2 `snocOL`
3483 instr (primRepToSize pk) src1 src2 dst
3484 else if pk1 == FloatRep then
3485 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3486 instr DF tmp src2 dst
3488 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3489 instr DF src1 tmp dst
3491 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3494 trivialUCode instr x
3495 = getRegister x `thenNat` \ register ->
3496 getNewRegNCG IntRep `thenNat` \ tmp ->
3498 code = registerCode register tmp
3499 src = registerName register tmp
3500 code__2 dst = code `snocOL` instr (RIReg src) dst
3502 returnNat (Any IntRep code__2)
3505 trivialUFCode pk instr x
3506 = getRegister x `thenNat` \ register ->
3507 getNewRegNCG pk `thenNat` \ tmp ->
3509 code = registerCode register tmp
3510 src = registerName register tmp
3511 code__2 dst = code `snocOL` instr src dst
3513 returnNat (Any pk code__2)
3515 #endif {- sparc_TARGET_ARCH -}
3517 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3520 %************************************************************************
3522 \subsubsection{Coercing to/from integer/floating-point...}
3524 %************************************************************************
3526 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3527 conversions. We have to store temporaries in memory to move
3528 between the integer and the floating point register sets.
3530 @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
3531 pretend, on sparc at least, that double and float regs are seperate
3532 kinds, so the value has to be computed into one kind before being
3533 explicitly "converted" to live in the other kind.
3536 coerceInt2FP :: PrimRep -> StixExpr -> NatM Register
3537 coerceFP2Int :: PrimRep -> StixExpr -> NatM Register
3539 coerceDbl2Flt :: StixExpr -> NatM Register
3540 coerceFlt2Dbl :: StixExpr -> NatM Register
3544 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3546 #if alpha_TARGET_ARCH
3549 = getRegister x `thenNat` \ register ->
3550 getNewRegNCG IntRep `thenNat` \ reg ->
3552 code = registerCode register reg
3553 src = registerName register reg
3555 code__2 dst = code . mkSeqInstrs [
3557 LD TF dst (spRel 0),
3560 returnNat (Any DoubleRep code__2)
3564 = getRegister x `thenNat` \ register ->
3565 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3567 code = registerCode register tmp
3568 src = registerName register tmp
3570 code__2 dst = code . mkSeqInstrs [
3572 ST TF tmp (spRel 0),
3575 returnNat (Any IntRep code__2)
3577 #endif {- alpha_TARGET_ARCH -}
3579 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3581 #if i386_TARGET_ARCH
3584 = getRegister x `thenNat` \ register ->
3585 getNewRegNCG IntRep `thenNat` \ reg ->
3587 code = registerCode register reg
3588 src = registerName register reg
3589 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3590 code__2 dst = code `snocOL` opc src dst
3592 returnNat (Any pk code__2)
3595 coerceFP2Int fprep x
3596 = getRegister x `thenNat` \ register ->
3597 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3599 code = registerCode register tmp
3600 src = registerName register tmp
3601 pk = registerRep register
3603 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3604 code__2 dst = code `snocOL` opc src dst
3606 returnNat (Any IntRep code__2)
3609 coerceDbl2Flt x = panic "MachCode.coerceDbl2Flt: unused on x86"
3610 coerceFlt2Dbl x = panic "MachCode.coerceFlt2Dbl: unused on x86"
3612 #endif {- i386_TARGET_ARCH -}
3614 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3616 #if sparc_TARGET_ARCH
3619 = getRegister x `thenNat` \ register ->
3620 getNewRegNCG IntRep `thenNat` \ reg ->
3622 code = registerCode register reg
3623 src = registerName register reg
3625 code__2 dst = code `appOL` toOL [
3626 ST W src (spRel (-2)),
3627 LD W (spRel (-2)) dst,
3628 FxTOy W (primRepToSize pk) dst dst]
3630 returnNat (Any pk code__2)
3633 coerceFP2Int fprep x
3634 = ASSERT(fprep == DoubleRep || fprep == FloatRep)
3635 getRegister x `thenNat` \ register ->
3636 getNewRegNCG fprep `thenNat` \ reg ->
3637 getNewRegNCG FloatRep `thenNat` \ tmp ->
3639 code = registerCode register reg
3640 src = registerName register reg
3641 code__2 dst = code `appOL` toOL [
3642 FxTOy (primRepToSize fprep) W src tmp,
3643 ST W tmp (spRel (-2)),
3644 LD W (spRel (-2)) dst]
3646 returnNat (Any IntRep code__2)
3650 = getRegister x `thenNat` \ register ->
3651 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3652 let code = registerCode register tmp
3653 src = registerName register tmp
3655 returnNat (Any FloatRep
3656 (\dst -> code `snocOL` FxTOy DF F src dst))
3660 = getRegister x `thenNat` \ register ->
3661 getNewRegNCG FloatRep `thenNat` \ tmp ->
3662 let code = registerCode register tmp
3663 src = registerName register tmp
3665 returnNat (Any DoubleRep
3666 (\dst -> code `snocOL` FxTOy F DF src dst))
3668 #endif {- sparc_TARGET_ARCH -}
3670 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -