3 -----------------------------------------------------------------------------
5 -- Generating machine code (instruction selection)
7 -- (c) The University of Glasgow 1996-2004
9 -----------------------------------------------------------------------------
11 -- This is a big module, but, if you pay attention to
12 -- (a) the sectioning, (b) the type signatures, and
13 -- (c) the #if blah_TARGET_ARCH} things, the
14 -- structure should not be too overwhelming.
23 #include "HsVersions.h"
24 #include "nativeGen/NCG.h"
40 -- Our intermediate code:
42 import PprCmm ( pprExpr )
47 import StaticFlags ( opt_PIC )
49 import qualified Outputable as O
53 import Control.Monad ( mapAndUnzipM )
58 -- -----------------------------------------------------------------------------
59 -- Top-level of the instruction selector
61 -- | 'InstrBlock's are the insn sequences generated by the insn selectors.
62 -- They are really trees of insns to facilitate fast appending, where a
63 -- left-to-right traversal (pre-order?) yields the insns in the correct
69 -> NatM [NatCmmTop Instr]
71 cmmTopCodeGen dflags (CmmProc info lab params (ListGraph blocks)) = do
72 (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
73 picBaseMb <- getPicBaseMaybeNat
74 let proc = CmmProc info lab params (ListGraph $ concat nat_blocks)
75 tops = proc : concat statics
76 os = platformOS $ targetPlatform dflags
78 Just picBase -> initializePicBase_ppc ArchPPC os picBase tops
79 Nothing -> return tops
81 cmmTopCodeGen dflags (CmmData sec dat) = do
82 return [CmmData sec dat] -- no translation, we just use CmmStatic
86 -> NatM ( [NatBasicBlock Instr]
89 basicBlockCodeGen (BasicBlock id stmts) = do
90 instrs <- stmtsToInstrs stmts
91 -- code generation may introduce new basic block boundaries, which
92 -- are indicated by the NEWBLOCK instruction. We must split up the
93 -- instruction stream into basic blocks again. Also, we extract
96 (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs
98 mkBlocks (NEWBLOCK id) (instrs,blocks,statics)
99 = ([], BasicBlock id instrs : blocks, statics)
100 mkBlocks (LDATA sec dat) (instrs,blocks,statics)
101 = (instrs, blocks, CmmData sec dat:statics)
102 mkBlocks instr (instrs,blocks,statics)
103 = (instr:instrs, blocks, statics)
105 return (BasicBlock id top : other_blocks, statics)
107 stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
109 = do instrss <- mapM stmtToInstrs stmts
110 return (concatOL instrss)
112 stmtToInstrs :: CmmStmt -> NatM InstrBlock
113 stmtToInstrs stmt = case stmt of
114 CmmNop -> return nilOL
115 CmmComment s -> return (unitOL (COMMENT s))
118 | isFloatType ty -> assignReg_FltCode size reg src
119 #if WORD_SIZE_IN_BITS==32
120 | isWord64 ty -> assignReg_I64Code reg src
122 | otherwise -> assignReg_IntCode size reg src
123 where ty = cmmRegType reg
124 size = cmmTypeSize ty
127 | isFloatType ty -> assignMem_FltCode size addr src
128 #if WORD_SIZE_IN_BITS==32
129 | isWord64 ty -> assignMem_I64Code addr src
131 | otherwise -> assignMem_IntCode size addr src
132 where ty = cmmExprType src
133 size = cmmTypeSize ty
135 CmmCall target result_regs args _ _
136 -> genCCall target result_regs args
138 CmmBranch id -> genBranch id
139 CmmCondBranch arg id -> genCondJump id arg
140 CmmSwitch arg ids -> genSwitch arg ids
141 CmmJump arg params -> genJump arg
143 panic "stmtToInstrs: return statement should have been cps'd away"
146 --------------------------------------------------------------------------------
147 -- | 'InstrBlock's are the insn sequences generated by the insn selectors.
148 -- They are really trees of insns to facilitate fast appending, where a
149 -- left-to-right traversal yields the insns in the correct order.
155 -- | Register's passed up the tree. If the stix code forces the register
156 -- to live in a pre-decided machine register, it comes out as @Fixed@;
157 -- otherwise, it comes out as @Any@, and the parent can decide which
158 -- register to put it in.
161 = Fixed Size Reg InstrBlock
162 | Any Size (Reg -> InstrBlock)
165 swizzleRegisterRep :: Register -> Size -> Register
166 swizzleRegisterRep (Fixed _ reg code) size = Fixed size reg code
167 swizzleRegisterRep (Any _ codefn) size = Any size codefn
170 -- | Grab the Reg for a CmmReg
171 getRegisterReg :: CmmReg -> Reg
173 getRegisterReg (CmmLocal (LocalReg u pk))
174 = mkVReg u (cmmTypeSize pk)
176 getRegisterReg (CmmGlobal mid)
177 = case get_GlobalReg_reg_or_addr mid of
178 Left (RealReg rrno) -> RealReg rrno
179 _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
180 -- By this stage, the only MagicIds remaining should be the
181 -- ones which map to a real machine register on this
182 -- platform. Hence ...
186 Now, given a tree (the argument to an CmmLoad) that references memory,
187 produce a suitable addressing mode.
189 A Rule of the Game (tm) for Amodes: use of the addr bit must
190 immediately follow use of the code part, since the code part puts
191 values in registers which the addr then refers to. So you can't put
192 anything in between, lest it overwrite some of those registers. If
193 you need to do some other computation between the code part and use of
194 the addr bit, first store the effective address from the amode in a
195 temporary, then do the other computation, and then use the temporary:
199 ... other computation ...
204 -- | Check whether an integer will fit in 32 bits.
205 -- A CmmInt is intended to be truncated to the appropriate
206 -- number of bits, so here we truncate it to Int64. This is
207 -- important because e.g. -1 as a CmmInt might be either
208 -- -1 or 18446744073709551615.
210 is32BitInteger :: Integer -> Bool
211 is32BitInteger i = i64 <= 0x7fffffff && i64 >= -0x80000000
212 where i64 = fromIntegral i :: Int64
215 -- | Convert a BlockId to some CmmStatic data
216 jumpTableEntry :: Maybe BlockId -> CmmStatic
217 jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordWidth)
218 jumpTableEntry (Just (BlockId id)) = CmmStaticLit (CmmLabel blockLabel)
219 where blockLabel = mkAsmTempLabel id
223 -- -----------------------------------------------------------------------------
224 -- General things for putting together code sequences
226 -- Expand CmmRegOff. ToDo: should we do it this way around, or convert
227 -- CmmExprs into CmmRegOff?
228 mangleIndexTree :: CmmExpr -> CmmExpr
229 mangleIndexTree (CmmRegOff reg off)
230 = CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]
231 where width = typeWidth (cmmRegType reg)
234 = panic "PPC.CodeGen.mangleIndexTree: no match"
236 -- -----------------------------------------------------------------------------
237 -- Code gen for 64-bit arithmetic on 32-bit platforms
240 Simple support for generating 64-bit code (ie, 64 bit values and 64
241 bit assignments) on 32-bit platforms. Unlike the main code generator
242 we merely shoot for generating working code as simply as possible, and
243 pay little attention to code quality. Specifically, there is no
244 attempt to deal cleverly with the fixed-vs-floating register
245 distinction; all values are generated into (pairs of) floating
246 registers, even if this would mean some redundant reg-reg moves as a
247 result. Only one of the VRegUniques is returned, since it will be
248 of the VRegUniqueLo form, and the upper-half VReg can be determined
249 by applying getHiVRegFromLo to it.
252 data ChildCode64 -- a.k.a "Register64"
255 Reg -- the lower 32-bit temporary which contains the
256 -- result; use getHiVRegFromLo to find the other
257 -- VRegUnique. Rules of this simplified insn
258 -- selection game are therefore that the returned
259 -- Reg may be modified
262 -- | The dual to getAnyReg: compute an expression into a register, but
263 -- we don't mind which one it is.
264 getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)
266 r <- getRegister expr
269 tmp <- getNewRegNat rep
270 return (tmp, code tmp)
274 getI64Amodes :: CmmExpr -> NatM (AddrMode, AddrMode, InstrBlock)
275 getI64Amodes addrTree = do
276 Amode hi_addr addr_code <- getAmode addrTree
277 case addrOffset hi_addr 4 of
278 Just lo_addr -> return (hi_addr, lo_addr, addr_code)
279 Nothing -> do (hi_ptr, code) <- getSomeReg addrTree
280 return (AddrRegImm hi_ptr (ImmInt 0),
281 AddrRegImm hi_ptr (ImmInt 4),
285 assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock
286 assignMem_I64Code addrTree valueTree = do
287 (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
288 ChildCode64 vcode rlo <- iselExpr64 valueTree
290 rhi = getHiVRegFromLo rlo
293 mov_hi = ST II32 rhi hi_addr
294 mov_lo = ST II32 rlo lo_addr
296 return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
299 assignReg_I64Code :: CmmReg -> CmmExpr -> NatM InstrBlock
300 assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
301 ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
303 r_dst_lo = mkVReg u_dst II32
304 r_dst_hi = getHiVRegFromLo r_dst_lo
305 r_src_hi = getHiVRegFromLo r_src_lo
306 mov_lo = MR r_dst_lo r_src_lo
307 mov_hi = MR r_dst_hi r_src_hi
310 vcode `snocOL` mov_lo `snocOL` mov_hi
313 assignReg_I64Code lvalue valueTree
314 = panic "assignReg_I64Code(powerpc): invalid lvalue"
317 iselExpr64 :: CmmExpr -> NatM ChildCode64
318 iselExpr64 (CmmLoad addrTree ty) | isWord64 ty = do
319 (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
320 (rlo, rhi) <- getNewRegPairNat II32
321 let mov_hi = LD II32 rhi hi_addr
322 mov_lo = LD II32 rlo lo_addr
323 return $ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi)
326 iselExpr64 (CmmReg (CmmLocal (LocalReg vu ty))) | isWord64 ty
327 = return (ChildCode64 nilOL (mkVReg vu II32))
329 iselExpr64 (CmmLit (CmmInt i _)) = do
330 (rlo,rhi) <- getNewRegPairNat II32
332 half0 = fromIntegral (fromIntegral i :: Word16)
333 half1 = fromIntegral ((fromIntegral i `shiftR` 16) :: Word16)
334 half2 = fromIntegral ((fromIntegral i `shiftR` 32) :: Word16)
335 half3 = fromIntegral ((fromIntegral i `shiftR` 48) :: Word16)
338 LIS rlo (ImmInt half1),
339 OR rlo rlo (RIImm $ ImmInt half0),
340 LIS rhi (ImmInt half3),
341 OR rlo rlo (RIImm $ ImmInt half2)
344 return (ChildCode64 code rlo)
346 iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
347 ChildCode64 code1 r1lo <- iselExpr64 e1
348 ChildCode64 code2 r2lo <- iselExpr64 e2
349 (rlo,rhi) <- getNewRegPairNat II32
351 r1hi = getHiVRegFromLo r1lo
352 r2hi = getHiVRegFromLo r2lo
355 toOL [ ADDC rlo r1lo r2lo,
358 return (ChildCode64 code rlo)
360 iselExpr64 (CmmMachOp (MO_UU_Conv W32 W64) [expr]) = do
361 (expr_reg,expr_code) <- getSomeReg expr
362 (rlo, rhi) <- getNewRegPairNat II32
363 let mov_hi = LI rhi (ImmInt 0)
364 mov_lo = MR rlo expr_reg
365 return $ ChildCode64 (expr_code `snocOL` mov_lo `snocOL` mov_hi)
368 = pprPanic "iselExpr64(powerpc)" (ppr expr)
372 getRegister :: CmmExpr -> NatM Register
374 getRegister (CmmReg reg)
375 = return (Fixed (cmmTypeSize (cmmRegType reg))
376 (getRegisterReg reg) nilOL)
378 getRegister tree@(CmmRegOff _ _)
379 = getRegister (mangleIndexTree tree)
382 #if WORD_SIZE_IN_BITS==32
383 -- for 32-bit architectuers, support some 64 -> 32 bit conversions:
384 -- TO_W_(x), TO_W_(x >> 32)
386 getRegister (CmmMachOp (MO_UU_Conv W64 W32)
387 [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]]) = do
388 ChildCode64 code rlo <- iselExpr64 x
389 return $ Fixed II32 (getHiVRegFromLo rlo) code
391 getRegister (CmmMachOp (MO_SS_Conv W64 W32)
392 [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]]) = do
393 ChildCode64 code rlo <- iselExpr64 x
394 return $ Fixed II32 (getHiVRegFromLo rlo) code
396 getRegister (CmmMachOp (MO_UU_Conv W64 W32) [x]) = do
397 ChildCode64 code rlo <- iselExpr64 x
398 return $ Fixed II32 rlo code
400 getRegister (CmmMachOp (MO_SS_Conv W64 W32) [x]) = do
401 ChildCode64 code rlo <- iselExpr64 x
402 return $ Fixed II32 rlo code
407 getRegister (CmmLoad mem pk)
410 Amode addr addr_code <- getAmode mem
411 let code dst = ASSERT((regClass dst == RcDouble) == isFloatType pk)
412 addr_code `snocOL` LD size dst addr
413 return (Any size code)
414 where size = cmmTypeSize pk
416 -- catch simple cases of zero- or sign-extended load
417 getRegister (CmmMachOp (MO_UU_Conv W8 W32) [CmmLoad mem _]) = do
418 Amode addr addr_code <- getAmode mem
419 return (Any II32 (\dst -> addr_code `snocOL` LD II8 dst addr))
421 -- Note: there is no Load Byte Arithmetic instruction, so no signed case here
423 getRegister (CmmMachOp (MO_UU_Conv W16 W32) [CmmLoad mem _]) = do
424 Amode addr addr_code <- getAmode mem
425 return (Any II32 (\dst -> addr_code `snocOL` LD II16 dst addr))
427 getRegister (CmmMachOp (MO_SS_Conv W16 W32) [CmmLoad mem _]) = do
428 Amode addr addr_code <- getAmode mem
429 return (Any II32 (\dst -> addr_code `snocOL` LA II16 dst addr))
431 getRegister (CmmMachOp mop [x]) -- unary MachOps
433 MO_Not rep -> triv_ucode_int rep NOT
435 MO_F_Neg w -> triv_ucode_float w FNEG
436 MO_S_Neg w -> triv_ucode_int w NEG
438 MO_FF_Conv W64 W32 -> trivialUCode FF32 FRSP x
439 MO_FF_Conv W32 W64 -> conversionNop FF64 x
441 MO_FS_Conv from to -> coerceFP2Int from to x
442 MO_SF_Conv from to -> coerceInt2FP from to x
445 | from == to -> conversionNop (intSize to) x
447 -- narrowing is a nop: we treat the high bits as undefined
448 MO_SS_Conv W32 to -> conversionNop (intSize to) x
449 MO_SS_Conv W16 W8 -> conversionNop II8 x
450 MO_SS_Conv W8 to -> triv_ucode_int to (EXTS II8)
451 MO_SS_Conv W16 to -> triv_ucode_int to (EXTS II16)
454 | from == to -> conversionNop (intSize to) x
455 -- narrowing is a nop: we treat the high bits as undefined
456 MO_UU_Conv W32 to -> conversionNop (intSize to) x
457 MO_UU_Conv W16 W8 -> conversionNop II8 x
458 MO_UU_Conv W8 to -> trivialCode to False AND x (CmmLit (CmmInt 255 W32))
459 MO_UU_Conv W16 to -> trivialCode to False AND x (CmmLit (CmmInt 65535 W32))
460 _ -> panic "PPC.CodeGen.getRegister: no match"
463 triv_ucode_int width instr = trivialUCode (intSize width) instr x
464 triv_ucode_float width instr = trivialUCode (floatSize width) instr x
466 conversionNop new_size expr
467 = do e_code <- getRegister expr
468 return (swizzleRegisterRep e_code new_size)
470 getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
472 MO_F_Eq w -> condFltReg EQQ x y
473 MO_F_Ne w -> condFltReg NE x y
474 MO_F_Gt w -> condFltReg GTT x y
475 MO_F_Ge w -> condFltReg GE x y
476 MO_F_Lt w -> condFltReg LTT x y
477 MO_F_Le w -> condFltReg LE x y
479 MO_Eq rep -> condIntReg EQQ (extendUExpr rep x) (extendUExpr rep y)
480 MO_Ne rep -> condIntReg NE (extendUExpr rep x) (extendUExpr rep y)
482 MO_S_Gt rep -> condIntReg GTT (extendSExpr rep x) (extendSExpr rep y)
483 MO_S_Ge rep -> condIntReg GE (extendSExpr rep x) (extendSExpr rep y)
484 MO_S_Lt rep -> condIntReg LTT (extendSExpr rep x) (extendSExpr rep y)
485 MO_S_Le rep -> condIntReg LE (extendSExpr rep x) (extendSExpr rep y)
487 MO_U_Gt rep -> condIntReg GU (extendUExpr rep x) (extendUExpr rep y)
488 MO_U_Ge rep -> condIntReg GEU (extendUExpr rep x) (extendUExpr rep y)
489 MO_U_Lt rep -> condIntReg LU (extendUExpr rep x) (extendUExpr rep y)
490 MO_U_Le rep -> condIntReg LEU (extendUExpr rep x) (extendUExpr rep y)
492 MO_F_Add w -> triv_float w FADD
493 MO_F_Sub w -> triv_float w FSUB
494 MO_F_Mul w -> triv_float w FMUL
495 MO_F_Quot w -> triv_float w FDIV
497 -- optimize addition with 32-bit immediate
501 CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate W32 True (-imm)
502 -> trivialCode W32 True ADD x (CmmLit $ CmmInt imm immrep)
505 (src, srcCode) <- getSomeReg x
506 let imm = litToImm lit
507 code dst = srcCode `appOL` toOL [
508 ADDIS dst src (HA imm),
509 ADD dst dst (RIImm (LO imm))
511 return (Any II32 code)
512 _ -> trivialCode W32 True ADD x y
514 MO_Add rep -> trivialCode rep True ADD x y
516 case y of -- subfi ('substract from' with immediate) doesn't exist
517 CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate rep True (-imm)
518 -> trivialCode rep True ADD x (CmmLit $ CmmInt (-imm) immrep)
519 _ -> trivialCodeNoImm' (intSize rep) SUBF y x
521 MO_Mul rep -> trivialCode rep True MULLW x y
523 MO_S_MulMayOflo W32 -> trivialCodeNoImm' II32 MULLW_MayOflo x y
525 MO_S_MulMayOflo rep -> panic "S_MulMayOflo (rep /= II32): not implemented"
526 MO_U_MulMayOflo rep -> panic "U_MulMayOflo: not implemented"
528 MO_S_Quot rep -> trivialCodeNoImm' (intSize rep) DIVW (extendSExpr rep x) (extendSExpr rep y)
529 MO_U_Quot rep -> trivialCodeNoImm' (intSize rep) DIVWU (extendUExpr rep x) (extendUExpr rep y)
531 MO_S_Rem rep -> remainderCode rep DIVW (extendSExpr rep x) (extendSExpr rep y)
532 MO_U_Rem rep -> remainderCode rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
534 MO_And rep -> trivialCode rep False AND x y
535 MO_Or rep -> trivialCode rep False OR x y
536 MO_Xor rep -> trivialCode rep False XOR x y
538 MO_Shl rep -> trivialCode rep False SLW x y
539 MO_S_Shr rep -> trivialCode rep False SRAW (extendSExpr rep x) y
540 MO_U_Shr rep -> trivialCode rep False SRW (extendUExpr rep x) y
541 _ -> panic "PPC.CodeGen.getRegister: no match"
544 triv_float :: Width -> (Size -> Reg -> Reg -> Reg -> Instr) -> NatM Register
545 triv_float width instr = trivialCodeNoImm (floatSize width) instr x y
547 getRegister (CmmLit (CmmInt i rep))
548 | Just imm <- makeImmediate rep True i
550 code dst = unitOL (LI dst imm)
552 return (Any (intSize rep) code)
554 getRegister (CmmLit (CmmFloat f frep)) = do
555 lbl <- getNewLabelNat
556 dflags <- getDynFlagsNat
557 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
558 Amode addr addr_code <- getAmode dynRef
559 let size = floatSize frep
561 LDATA ReadOnlyData [CmmDataLabel lbl,
562 CmmStaticLit (CmmFloat f frep)]
563 `consOL` (addr_code `snocOL` LD size dst addr)
564 return (Any size code)
566 getRegister (CmmLit lit)
567 = let rep = cmmLitType lit
571 ADD dst dst (RIImm (LO imm))
573 in return (Any (cmmTypeSize rep) code)
575 getRegister other = pprPanic "getRegister(ppc)" (pprExpr other)
577 -- extend?Rep: wrap integer expression of type rep
578 -- in a conversion to II32
579 extendSExpr W32 x = x
580 extendSExpr rep x = CmmMachOp (MO_SS_Conv rep W32) [x]
581 extendUExpr W32 x = x
582 extendUExpr rep x = CmmMachOp (MO_UU_Conv rep W32) [x]
584 -- -----------------------------------------------------------------------------
585 -- The 'Amode' type: Memory addressing modes passed up the tree.
588 = Amode AddrMode InstrBlock
591 Now, given a tree (the argument to an CmmLoad) that references memory,
592 produce a suitable addressing mode.
594 A Rule of the Game (tm) for Amodes: use of the addr bit must
595 immediately follow use of the code part, since the code part puts
596 values in registers which the addr then refers to. So you can't put
597 anything in between, lest it overwrite some of those registers. If
598 you need to do some other computation between the code part and use of
599 the addr bit, first store the effective address from the amode in a
600 temporary, then do the other computation, and then use the temporary:
604 ... other computation ...
608 getAmode :: CmmExpr -> NatM Amode
609 getAmode tree@(CmmRegOff _ _) = getAmode (mangleIndexTree tree)
611 getAmode (CmmMachOp (MO_Sub W32) [x, CmmLit (CmmInt i _)])
612 | Just off <- makeImmediate W32 True (-i)
614 (reg, code) <- getSomeReg x
615 return (Amode (AddrRegImm reg off) code)
618 getAmode (CmmMachOp (MO_Add W32) [x, CmmLit (CmmInt i _)])
619 | Just off <- makeImmediate W32 True i
621 (reg, code) <- getSomeReg x
622 return (Amode (AddrRegImm reg off) code)
624 -- optimize addition with 32-bit immediate
626 getAmode (CmmMachOp (MO_Add W32) [x, CmmLit lit])
628 tmp <- getNewRegNat II32
629 (src, srcCode) <- getSomeReg x
630 let imm = litToImm lit
631 code = srcCode `snocOL` ADDIS tmp src (HA imm)
632 return (Amode (AddrRegImm tmp (LO imm)) code)
634 getAmode (CmmLit lit)
636 tmp <- getNewRegNat II32
637 let imm = litToImm lit
638 code = unitOL (LIS tmp (HA imm))
639 return (Amode (AddrRegImm tmp (LO imm)) code)
641 getAmode (CmmMachOp (MO_Add W32) [x, y])
643 (regX, codeX) <- getSomeReg x
644 (regY, codeY) <- getSomeReg y
645 return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))
649 (reg, code) <- getSomeReg other
652 return (Amode (AddrRegImm reg off) code)
656 -- The 'CondCode' type: Condition codes passed up the tree.
658 = CondCode Bool Cond InstrBlock
660 -- Set up a condition code for a conditional branch.
662 getCondCode :: CmmExpr -> NatM CondCode
664 -- almost the same as everywhere else - but we need to
665 -- extend small integers to 32 bit first
667 getCondCode (CmmMachOp mop [x, y])
669 MO_F_Eq W32 -> condFltCode EQQ x y
670 MO_F_Ne W32 -> condFltCode NE x y
671 MO_F_Gt W32 -> condFltCode GTT x y
672 MO_F_Ge W32 -> condFltCode GE x y
673 MO_F_Lt W32 -> condFltCode LTT x y
674 MO_F_Le W32 -> condFltCode LE x y
676 MO_F_Eq W64 -> condFltCode EQQ x y
677 MO_F_Ne W64 -> condFltCode NE x y
678 MO_F_Gt W64 -> condFltCode GTT x y
679 MO_F_Ge W64 -> condFltCode GE x y
680 MO_F_Lt W64 -> condFltCode LTT x y
681 MO_F_Le W64 -> condFltCode LE x y
683 MO_Eq rep -> condIntCode EQQ (extendUExpr rep x) (extendUExpr rep y)
684 MO_Ne rep -> condIntCode NE (extendUExpr rep x) (extendUExpr rep y)
686 MO_S_Gt rep -> condIntCode GTT (extendSExpr rep x) (extendSExpr rep y)
687 MO_S_Ge rep -> condIntCode GE (extendSExpr rep x) (extendSExpr rep y)
688 MO_S_Lt rep -> condIntCode LTT (extendSExpr rep x) (extendSExpr rep y)
689 MO_S_Le rep -> condIntCode LE (extendSExpr rep x) (extendSExpr rep y)
691 MO_U_Gt rep -> condIntCode GU (extendUExpr rep x) (extendUExpr rep y)
692 MO_U_Ge rep -> condIntCode GEU (extendUExpr rep x) (extendUExpr rep y)
693 MO_U_Lt rep -> condIntCode LU (extendUExpr rep x) (extendUExpr rep y)
694 MO_U_Le rep -> condIntCode LEU (extendUExpr rep x) (extendUExpr rep y)
696 other -> pprPanic "getCondCode(powerpc)" (pprMachOp mop)
698 getCondCode other = panic "getCondCode(2)(powerpc)"
702 -- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
703 -- passed back up the tree.
705 condIntCode, condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode
707 -- ###FIXME: I16 and I8!
708 condIntCode cond x (CmmLit (CmmInt y rep))
709 | Just src2 <- makeImmediate rep (not $ condUnsigned cond) y
711 (src1, code) <- getSomeReg x
713 code' = code `snocOL`
714 (if condUnsigned cond then CMPL else CMP) II32 src1 (RIImm src2)
715 return (CondCode False cond code')
717 condIntCode cond x y = do
718 (src1, code1) <- getSomeReg x
719 (src2, code2) <- getSomeReg y
721 code' = code1 `appOL` code2 `snocOL`
722 (if condUnsigned cond then CMPL else CMP) II32 src1 (RIReg src2)
723 return (CondCode False cond code')
725 condFltCode cond x y = do
726 (src1, code1) <- getSomeReg x
727 (src2, code2) <- getSomeReg y
729 code' = code1 `appOL` code2 `snocOL` FCMP src1 src2
730 code'' = case cond of -- twiddle CR to handle unordered case
731 GE -> code' `snocOL` CRNOR ltbit eqbit gtbit
732 LE -> code' `snocOL` CRNOR gtbit eqbit ltbit
735 ltbit = 0 ; eqbit = 2 ; gtbit = 1
736 return (CondCode True cond code'')
740 -- -----------------------------------------------------------------------------
741 -- Generating assignments
743 -- Assignments are really at the heart of the whole code generation
744 -- business. Almost all top-level nodes of any real importance are
745 -- assignments, which correspond to loads, stores, or register
746 -- transfers. If we're really lucky, some of the register transfers
747 -- will go away, because we can use the destination register to
748 -- complete the code generation for the right hand side. This only
749 -- fails when the right hand side is forced into a fixed register
750 -- (e.g. the result of a call).
752 assignMem_IntCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
753 assignReg_IntCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
755 assignMem_FltCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
756 assignReg_FltCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
758 assignMem_IntCode pk addr src = do
759 (srcReg, code) <- getSomeReg src
760 Amode dstAddr addr_code <- getAmode addr
761 return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
763 -- dst is a reg, but src could be anything
764 assignReg_IntCode _ reg src
768 Any _ code -> code dst
769 Fixed _ freg fcode -> fcode `snocOL` MR dst freg
771 dst = getRegisterReg reg
776 assignMem_FltCode = assignMem_IntCode
777 assignReg_FltCode = assignReg_IntCode
781 genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock
783 genJump (CmmLit (CmmLabel lbl))
784 = return (unitOL $ JMP lbl)
788 (target,code) <- getSomeReg tree
789 return (code `snocOL` MTCTR target `snocOL` BCTR [])
792 -- -----------------------------------------------------------------------------
793 -- Unconditional branches
794 genBranch :: BlockId -> NatM InstrBlock
795 genBranch = return . toOL . mkJumpInstr
798 -- -----------------------------------------------------------------------------
802 Conditional jumps are always to local labels, so we can use branch
803 instructions. We peek at the arguments to decide what kind of
806 SPARC: First, we have to ensure that the condition codes are set
807 according to the supplied comparison operation. We generate slightly
808 different code for floating point comparisons, because a floating
809 point operation cannot directly precede a @BF@. We assume the worst
810 and fill that slot with a @NOP@.
812 SPARC: Do not fill the delay slots here; you will confuse the register
818 :: BlockId -- the branch target
819 -> CmmExpr -- the condition on which to branch
822 genCondJump id bool = do
823 CondCode _ cond code <- getCondCode bool
824 return (code `snocOL` BCC cond id)
828 -- -----------------------------------------------------------------------------
829 -- Generating C calls
831 -- Now the biggest nightmare---calls. Most of the nastiness is buried in
832 -- @get_arg@, which moves the arguments to the correct registers/stack
833 -- locations. Apart from that, the code is easy.
835 -- (If applicable) Do not fill the delay slots here; you will confuse the
836 -- register allocator.
839 :: CmmCallTarget -- function to call
840 -> HintedCmmFormals -- where to put the result
841 -> HintedCmmActuals -- arguments (of mixed type)
845 #if darwin_TARGET_OS || linux_TARGET_OS
847 The PowerPC calling convention for Darwin/Mac OS X
848 is described in Apple's document
849 "Inside Mac OS X - Mach-O Runtime Architecture".
851 PowerPC Linux uses the System V Release 4 Calling Convention
852 for PowerPC. It is described in the
853 "System V Application Binary Interface PowerPC Processor Supplement".
855 Both conventions are similar:
856 Parameters may be passed in general-purpose registers starting at r3, in
857 floating point registers starting at f1, or on the stack.
859 But there are substantial differences:
860 * The number of registers used for parameter passing and the exact set of
861 nonvolatile registers differs (see MachRegs.lhs).
862 * On Darwin, stack space is always reserved for parameters, even if they are
863 passed in registers. The called routine may choose to save parameters from
864 registers to the corresponding space on the stack.
865 * On Darwin, a corresponding amount of GPRs is skipped when a floating point
866 parameter is passed in an FPR.
867 * SysV insists on either passing I64 arguments on the stack, or in two GPRs,
868 starting with an odd-numbered GPR. It may skip a GPR to achieve this.
869 Darwin just treats an I64 like two separate II32s (high word first).
870 * I64 and FF64 arguments are 8-byte aligned on the stack for SysV, but only
871 4-byte aligned like everything else on Darwin.
872 * The SysV spec claims that FF32 is represented as FF64 on the stack. GCC on
873 PowerPC Linux does not agree, so neither do we.
875 According to both conventions, The parameter area should be part of the
876 caller's stack frame, allocated in the caller's prologue code (large enough
877 to hold the parameter lists for all called routines). The NCG already
878 uses the stack for register spilling, leaving 64 bytes free at the top.
879 If we need a larger parameter area than that, we just allocate a new stack
880 frame just before ccalling.
884 genCCall (CmmPrim MO_WriteBarrier) _ _
885 = return $ unitOL LWSYNC
887 genCCall target dest_regs argsAndHints
888 = ASSERT (not $ any (`elem` [II8,II16]) $ map cmmTypeSize argReps)
889 -- we rely on argument promotion in the codeGen
891 (finalStack,passArgumentsCode,usedRegs) <- passArguments
893 allArgRegs allFPArgRegs
897 (labelOrExpr, reduceToFF32) <- case target of
898 CmmCallee (CmmLit (CmmLabel lbl)) conv -> return (Left lbl, False)
899 CmmCallee expr conv -> return (Right expr, False)
900 CmmPrim mop -> outOfLineFloatOp mop
902 let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
903 codeAfter = move_sp_up finalStack `appOL` moveResult reduceToFF32
908 `snocOL` BL lbl usedRegs
911 (dynReg, dynCode) <- getSomeReg dyn
913 `snocOL` MTCTR dynReg
915 `snocOL` BCTRL usedRegs
919 initialStackOffset = 24
920 -- size of linkage area + size of arguments, in bytes
921 stackDelta _finalStack = roundTo 16 $ (24 +) $ max 32 $ sum $
922 map (widthInBytes . typeWidth) argReps
923 #elif linux_TARGET_OS
924 initialStackOffset = 8
925 stackDelta finalStack = roundTo 16 finalStack
927 args = map hintlessCmm argsAndHints
928 argReps = map cmmExprType args
930 roundTo a x | x `mod` a == 0 = x
931 | otherwise = x + a - (x `mod` a)
933 move_sp_down finalStack
935 toOL [STU II32 sp (AddrRegImm sp (ImmInt (-delta))),
938 where delta = stackDelta finalStack
939 move_sp_up finalStack
941 toOL [ADD sp sp (RIImm (ImmInt delta)),
944 where delta = stackDelta finalStack
947 passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)
948 passArguments ((arg,arg_ty):args) gprs fprs stackOffset
949 accumCode accumUsed | isWord64 arg_ty =
951 ChildCode64 code vr_lo <- iselExpr64 arg
952 let vr_hi = getHiVRegFromLo vr_lo
959 (accumCode `appOL` code
960 `snocOL` storeWord vr_hi gprs stackOffset
961 `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))
962 ((take 2 gprs) ++ accumUsed)
964 storeWord vr (gpr:_) offset = MR gpr vr
965 storeWord vr [] offset = ST II32 vr (AddrRegImm sp (ImmInt offset))
967 #elif linux_TARGET_OS
968 let stackOffset' = roundTo 8 stackOffset
969 stackCode = accumCode `appOL` code
970 `snocOL` ST II32 vr_hi (AddrRegImm sp (ImmInt stackOffset'))
971 `snocOL` ST II32 vr_lo (AddrRegImm sp (ImmInt (stackOffset'+4)))
972 regCode hireg loreg =
973 accumCode `appOL` code
974 `snocOL` MR hireg vr_hi
975 `snocOL` MR loreg vr_lo
978 hireg : loreg : regs | even (length gprs) ->
979 passArguments args regs fprs stackOffset
980 (regCode hireg loreg) (hireg : loreg : accumUsed)
981 _skipped : hireg : loreg : regs ->
982 passArguments args regs fprs stackOffset
983 (regCode hireg loreg) (hireg : loreg : accumUsed)
984 _ -> -- only one or no regs left
985 passArguments args [] fprs (stackOffset'+8)
989 passArguments ((arg,rep):args) gprs fprs stackOffset accumCode accumUsed
990 | reg : _ <- regs = do
991 register <- getRegister arg
992 let code = case register of
993 Fixed _ freg fcode -> fcode `snocOL` MR reg freg
994 Any _ acode -> acode reg
999 -- The Darwin ABI requires that we reserve stack slots for register parameters
1000 (stackOffset + stackBytes)
1001 #elif linux_TARGET_OS
1002 -- ... the SysV ABI doesn't.
1005 (accumCode `appOL` code)
1008 (vr, code) <- getSomeReg arg
1012 (stackOffset' + stackBytes)
1013 (accumCode `appOL` code `snocOL` ST (cmmTypeSize rep) vr stackSlot)
1016 #if darwin_TARGET_OS
1017 -- stackOffset is at least 4-byte aligned
1018 -- The Darwin ABI is happy with that.
1019 stackOffset' = stackOffset
1021 -- ... the SysV ABI requires 8-byte alignment for doubles.
1022 stackOffset' | isFloatType rep && typeWidth rep == W64 =
1023 roundTo 8 stackOffset
1024 | otherwise = stackOffset
1026 stackSlot = AddrRegImm sp (ImmInt stackOffset')
1027 (nGprs, nFprs, stackBytes, regs) = case cmmTypeSize rep of
1028 II32 -> (1, 0, 4, gprs)
1029 #if darwin_TARGET_OS
1030 -- The Darwin ABI requires that we skip a corresponding number of GPRs when
1032 FF32 -> (1, 1, 4, fprs)
1033 FF64 -> (2, 1, 8, fprs)
1034 #elif linux_TARGET_OS
1035 -- ... the SysV ABI doesn't.
1036 FF32 -> (0, 1, 4, fprs)
1037 FF64 -> (0, 1, 8, fprs)
1040 moveResult reduceToFF32 =
1043 [CmmHinted dest _hint]
1044 | reduceToFF32 && isFloat32 rep -> unitOL (FRSP r_dest f1)
1045 | isFloat32 rep || isFloat64 rep -> unitOL (MR r_dest f1)
1046 | isWord64 rep -> toOL [MR (getHiVRegFromLo r_dest) r3,
1048 | otherwise -> unitOL (MR r_dest r3)
1049 where rep = cmmRegType (CmmLocal dest)
1050 r_dest = getRegisterReg (CmmLocal dest)
1052 outOfLineFloatOp mop =
1054 dflags <- getDynFlagsNat
1055 mopExpr <- cmmMakeDynamicReference dflags addImportNat CallReference $
1056 mkForeignLabel functionName Nothing True
1057 let mopLabelOrExpr = case mopExpr of
1058 CmmLit (CmmLabel lbl) -> Left lbl
1060 return (mopLabelOrExpr, reduce)
1062 (functionName, reduce) = case mop of
1063 MO_F32_Exp -> (fsLit "exp", True)
1064 MO_F32_Log -> (fsLit "log", True)
1065 MO_F32_Sqrt -> (fsLit "sqrt", True)
1067 MO_F32_Sin -> (fsLit "sin", True)
1068 MO_F32_Cos -> (fsLit "cos", True)
1069 MO_F32_Tan -> (fsLit "tan", True)
1071 MO_F32_Asin -> (fsLit "asin", True)
1072 MO_F32_Acos -> (fsLit "acos", True)
1073 MO_F32_Atan -> (fsLit "atan", True)
1075 MO_F32_Sinh -> (fsLit "sinh", True)
1076 MO_F32_Cosh -> (fsLit "cosh", True)
1077 MO_F32_Tanh -> (fsLit "tanh", True)
1078 MO_F32_Pwr -> (fsLit "pow", True)
1080 MO_F64_Exp -> (fsLit "exp", False)
1081 MO_F64_Log -> (fsLit "log", False)
1082 MO_F64_Sqrt -> (fsLit "sqrt", False)
1084 MO_F64_Sin -> (fsLit "sin", False)
1085 MO_F64_Cos -> (fsLit "cos", False)
1086 MO_F64_Tan -> (fsLit "tan", False)
1088 MO_F64_Asin -> (fsLit "asin", False)
1089 MO_F64_Acos -> (fsLit "acos", False)
1090 MO_F64_Atan -> (fsLit "atan", False)
1092 MO_F64_Sinh -> (fsLit "sinh", False)
1093 MO_F64_Cosh -> (fsLit "cosh", False)
1094 MO_F64_Tanh -> (fsLit "tanh", False)
1095 MO_F64_Pwr -> (fsLit "pow", False)
1096 other -> pprPanic "genCCall(ppc): unknown callish op"
1097 (pprCallishMachOp other)
1099 #else /* darwin_TARGET_OS || linux_TARGET_OS */
1100 genCCall = panic "PPC.CodeGen.genCCall: not defined for this os"
1104 -- -----------------------------------------------------------------------------
1105 -- Generating a table-branch
1107 genSwitch :: CmmExpr -> [Maybe BlockId] -> NatM InstrBlock
1111 (reg,e_code) <- getSomeReg expr
1112 tmp <- getNewRegNat II32
1113 lbl <- getNewLabelNat
1114 dflags <- getDynFlagsNat
1115 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
1116 (tableReg,t_code) <- getSomeReg $ dynRef
1118 jumpTable = map jumpTableEntryRel ids
1120 jumpTableEntryRel Nothing
1121 = CmmStaticLit (CmmInt 0 wordWidth)
1122 jumpTableEntryRel (Just (BlockId id))
1123 = CmmStaticLit (CmmLabelDiffOff blockLabel lbl 0)
1124 where blockLabel = mkAsmTempLabel id
1126 code = e_code `appOL` t_code `appOL` toOL [
1127 LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
1128 SLW tmp reg (RIImm (ImmInt 2)),
1129 LD II32 tmp (AddrRegReg tableReg tmp),
1130 ADD tmp tmp (RIReg tableReg),
1132 BCTR [ id | Just id <- ids ]
1137 (reg,e_code) <- getSomeReg expr
1138 tmp <- getNewRegNat II32
1139 lbl <- getNewLabelNat
1141 jumpTable = map jumpTableEntry ids
1143 code = e_code `appOL` toOL [
1144 LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
1145 SLW tmp reg (RIImm (ImmInt 2)),
1146 ADDIS tmp tmp (HA (ImmCLbl lbl)),
1147 LD II32 tmp (AddrRegImm tmp (LO (ImmCLbl lbl))),
1149 BCTR [ id | Just id <- ids ]
1154 -- -----------------------------------------------------------------------------
1155 -- 'condIntReg' and 'condFltReg': condition codes into registers
1157 -- Turn those condition codes into integers now (when they appear on
1158 -- the right hand side of an assignment).
1160 -- (If applicable) Do not fill the delay slots here; you will confuse the
1161 -- register allocator.
1163 condIntReg, condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register
1165 condReg :: NatM CondCode -> NatM Register
1166 condReg getCond = do
1167 CondCode _ cond cond_code <- getCond
1169 {- code dst = cond_code `appOL` toOL [
1178 code dst = cond_code
1182 RLWINM dst dst (bit + 1) 31 31
1185 negate_code | do_negate = unitOL (CRNOR bit bit bit)
1188 (bit, do_negate) = case cond of
1201 _ -> panic "PPC.CodeGen.codeReg: no match"
1203 return (Any II32 code)
1205 condIntReg cond x y = condReg (condIntCode cond x y)
1206 condFltReg cond x y = condReg (condFltCode cond x y)
1210 -- -----------------------------------------------------------------------------
1211 -- 'trivial*Code': deal with trivial instructions
1213 -- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',
1214 -- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.
1215 -- Only look for constants on the right hand side, because that's
1216 -- where the generic optimizer will have put them.
1218 -- Similarly, for unary instructions, we don't have to worry about
1219 -- matching an StInt as the argument, because genericOpt will already
1220 -- have handled the constant-folding.
1225 Wolfgang's PowerPC version of The Rules:
1227 A slightly modified version of The Rules to take advantage of the fact
1228 that PowerPC instructions work on all registers and don't implicitly
1229 clobber any fixed registers.
1231 * The only expression for which getRegister returns Fixed is (CmmReg reg).
1233 * If getRegister returns Any, then the code it generates may modify only:
1234 (a) fresh temporaries
1235 (b) the destination register
1236 It may *not* modify global registers, unless the global
1237 register happens to be the destination register.
1238 It may not clobber any other registers. In fact, only ccalls clobber any
1240 Also, it may not modify the counter register (used by genCCall).
1242 Corollary: If a getRegister for a subexpression returns Fixed, you need
1243 not move it to a fresh temporary before evaluating the next subexpression.
1244 The Fixed register won't be modified.
1245 Therefore, we don't need a counterpart for the x86's getStableReg on PPC.
1247 * SDM's First Rule is valid for PowerPC, too: subexpressions can depend on
1248 the value of the destination register.
1254 -> (Reg -> Reg -> RI -> Instr)
1259 trivialCode rep signed instr x (CmmLit (CmmInt y _))
1260 | Just imm <- makeImmediate rep signed y
1262 (src1, code1) <- getSomeReg x
1263 let code dst = code1 `snocOL` instr dst src1 (RIImm imm)
1264 return (Any (intSize rep) code)
1266 trivialCode rep _ instr x y = do
1267 (src1, code1) <- getSomeReg x
1268 (src2, code2) <- getSomeReg y
1269 let code dst = code1 `appOL` code2 `snocOL` instr dst src1 (RIReg src2)
1270 return (Any (intSize rep) code)
1272 trivialCodeNoImm' :: Size -> (Reg -> Reg -> Reg -> Instr)
1273 -> CmmExpr -> CmmExpr -> NatM Register
1274 trivialCodeNoImm' size instr x y = do
1275 (src1, code1) <- getSomeReg x
1276 (src2, code2) <- getSomeReg y
1277 let code dst = code1 `appOL` code2 `snocOL` instr dst src1 src2
1278 return (Any size code)
1280 trivialCodeNoImm :: Size -> (Size -> Reg -> Reg -> Reg -> Instr)
1281 -> CmmExpr -> CmmExpr -> NatM Register
1282 trivialCodeNoImm size instr x y = trivialCodeNoImm' size (instr size) x y
1287 -> (Reg -> Reg -> Instr)
1290 trivialUCode rep instr x = do
1291 (src, code) <- getSomeReg x
1292 let code' dst = code `snocOL` instr dst src
1293 return (Any rep code')
1295 -- There is no "remainder" instruction on the PPC, so we have to do
1297 -- The "div" parameter is the division instruction to use (DIVW or DIVWU)
1299 remainderCode :: Width -> (Reg -> Reg -> Reg -> Instr)
1300 -> CmmExpr -> CmmExpr -> NatM Register
1301 remainderCode rep div x y = do
1302 (src1, code1) <- getSomeReg x
1303 (src2, code2) <- getSomeReg y
1304 let code dst = code1 `appOL` code2 `appOL` toOL [
1306 MULLW dst dst (RIReg src2),
1309 return (Any (intSize rep) code)
1312 coerceInt2FP :: Width -> Width -> CmmExpr -> NatM Register
1313 coerceInt2FP fromRep toRep x = do
1314 (src, code) <- getSomeReg x
1315 lbl <- getNewLabelNat
1316 itmp <- getNewRegNat II32
1317 ftmp <- getNewRegNat FF64
1318 dflags <- getDynFlagsNat
1319 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
1320 Amode addr addr_code <- getAmode dynRef
1322 code' dst = code `appOL` maybe_exts `appOL` toOL [
1325 CmmStaticLit (CmmInt 0x43300000 W32),
1326 CmmStaticLit (CmmInt 0x80000000 W32)],
1327 XORIS itmp src (ImmInt 0x8000),
1328 ST II32 itmp (spRel 3),
1329 LIS itmp (ImmInt 0x4330),
1330 ST II32 itmp (spRel 2),
1331 LD FF64 ftmp (spRel 2)
1332 ] `appOL` addr_code `appOL` toOL [
1334 FSUB FF64 dst ftmp dst
1335 ] `appOL` maybe_frsp dst
1337 maybe_exts = case fromRep of
1338 W8 -> unitOL $ EXTS II8 src src
1339 W16 -> unitOL $ EXTS II16 src src
1341 _ -> panic "PPC.CodeGen.coerceInt2FP: no match"
1345 W32 -> unitOL $ FRSP dst dst
1347 _ -> panic "PPC.CodeGen.coerceInt2FP: no match"
1349 return (Any (floatSize toRep) code')
1351 coerceFP2Int :: Width -> Width -> CmmExpr -> NatM Register
1352 coerceFP2Int _ toRep x = do
1353 -- the reps don't really matter: F*->FF64 and II32->I* are no-ops
1354 (src, code) <- getSomeReg x
1355 tmp <- getNewRegNat FF64
1357 code' dst = code `appOL` toOL [
1358 -- convert to int in FP reg
1360 -- store value (64bit) from FP to stack
1361 ST FF64 tmp (spRel 2),
1362 -- read low word of value (high word is undefined)
1363 LD II32 dst (spRel 3)]
1364 return (Any (intSize toRep) code')