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 #if darwin_TARGET_OS || linux_TARGET_OS
63 -- -----------------------------------------------------------------------------
64 -- Top-level of the instruction selector
66 -- | 'InstrBlock's are the insn sequences generated by the insn selectors.
67 -- They are really trees of insns to facilitate fast appending, where a
68 -- left-to-right traversal (pre-order?) yields the insns in the correct
74 -> NatM [NatCmmTop Instr]
76 cmmTopCodeGen dflags (CmmProc info lab params (ListGraph blocks)) = do
77 (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
78 picBaseMb <- getPicBaseMaybeNat
79 let proc = CmmProc info lab params (ListGraph $ concat nat_blocks)
80 tops = proc : concat statics
81 os = platformOS $ targetPlatform dflags
83 Just picBase -> initializePicBase_ppc ArchPPC os picBase tops
84 Nothing -> return tops
86 cmmTopCodeGen dflags (CmmData sec dat) = do
87 return [CmmData sec dat] -- no translation, we just use CmmStatic
91 -> NatM ( [NatBasicBlock Instr]
94 basicBlockCodeGen (BasicBlock id stmts) = do
95 instrs <- stmtsToInstrs stmts
96 -- code generation may introduce new basic block boundaries, which
97 -- are indicated by the NEWBLOCK instruction. We must split up the
98 -- instruction stream into basic blocks again. Also, we extract
101 (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs
103 mkBlocks (NEWBLOCK id) (instrs,blocks,statics)
104 = ([], BasicBlock id instrs : blocks, statics)
105 mkBlocks (LDATA sec dat) (instrs,blocks,statics)
106 = (instrs, blocks, CmmData sec dat:statics)
107 mkBlocks instr (instrs,blocks,statics)
108 = (instr:instrs, blocks, statics)
110 return (BasicBlock id top : other_blocks, statics)
112 stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
114 = do instrss <- mapM stmtToInstrs stmts
115 return (concatOL instrss)
117 stmtToInstrs :: CmmStmt -> NatM InstrBlock
118 stmtToInstrs stmt = case stmt of
119 CmmNop -> return nilOL
120 CmmComment s -> return (unitOL (COMMENT s))
123 | isFloatType ty -> assignReg_FltCode size reg src
124 #if WORD_SIZE_IN_BITS==32
125 | isWord64 ty -> assignReg_I64Code reg src
127 | otherwise -> assignReg_IntCode size reg src
128 where ty = cmmRegType reg
129 size = cmmTypeSize ty
132 | isFloatType ty -> assignMem_FltCode size addr src
133 #if WORD_SIZE_IN_BITS==32
134 | isWord64 ty -> assignMem_I64Code addr src
136 | otherwise -> assignMem_IntCode size addr src
137 where ty = cmmExprType src
138 size = cmmTypeSize ty
140 CmmCall target result_regs args _ _
141 -> genCCall target result_regs args
143 CmmBranch id -> genBranch id
144 CmmCondBranch arg id -> genCondJump id arg
145 CmmSwitch arg ids -> genSwitch arg ids
146 CmmJump arg params -> genJump arg
148 panic "stmtToInstrs: return statement should have been cps'd away"
151 --------------------------------------------------------------------------------
152 -- | 'InstrBlock's are the insn sequences generated by the insn selectors.
153 -- They are really trees of insns to facilitate fast appending, where a
154 -- left-to-right traversal yields the insns in the correct order.
160 -- | Register's passed up the tree. If the stix code forces the register
161 -- to live in a pre-decided machine register, it comes out as @Fixed@;
162 -- otherwise, it comes out as @Any@, and the parent can decide which
163 -- register to put it in.
166 = Fixed Size Reg InstrBlock
167 | Any Size (Reg -> InstrBlock)
170 swizzleRegisterRep :: Register -> Size -> Register
171 swizzleRegisterRep (Fixed _ reg code) size = Fixed size reg code
172 swizzleRegisterRep (Any _ codefn) size = Any size codefn
175 -- | Grab the Reg for a CmmReg
176 getRegisterReg :: CmmReg -> Reg
178 getRegisterReg (CmmLocal (LocalReg u pk))
179 = mkVReg u (cmmTypeSize pk)
181 getRegisterReg (CmmGlobal mid)
182 = case get_GlobalReg_reg_or_addr mid of
183 Left (RealReg rrno) -> RealReg rrno
184 _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
185 -- By this stage, the only MagicIds remaining should be the
186 -- ones which map to a real machine register on this
187 -- platform. Hence ...
191 Now, given a tree (the argument to an CmmLoad) that references memory,
192 produce a suitable addressing mode.
194 A Rule of the Game (tm) for Amodes: use of the addr bit must
195 immediately follow use of the code part, since the code part puts
196 values in registers which the addr then refers to. So you can't put
197 anything in between, lest it overwrite some of those registers. If
198 you need to do some other computation between the code part and use of
199 the addr bit, first store the effective address from the amode in a
200 temporary, then do the other computation, and then use the temporary:
204 ... other computation ...
209 -- | Check whether an integer will fit in 32 bits.
210 -- A CmmInt is intended to be truncated to the appropriate
211 -- number of bits, so here we truncate it to Int64. This is
212 -- important because e.g. -1 as a CmmInt might be either
213 -- -1 or 18446744073709551615.
215 is32BitInteger :: Integer -> Bool
216 is32BitInteger i = i64 <= 0x7fffffff && i64 >= -0x80000000
217 where i64 = fromIntegral i :: Int64
220 -- | Convert a BlockId to some CmmStatic data
221 jumpTableEntry :: Maybe BlockId -> CmmStatic
222 jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordWidth)
223 jumpTableEntry (Just (BlockId id)) = CmmStaticLit (CmmLabel blockLabel)
224 where blockLabel = mkAsmTempLabel id
228 -- -----------------------------------------------------------------------------
229 -- General things for putting together code sequences
231 -- Expand CmmRegOff. ToDo: should we do it this way around, or convert
232 -- CmmExprs into CmmRegOff?
233 mangleIndexTree :: CmmExpr -> CmmExpr
234 mangleIndexTree (CmmRegOff reg off)
235 = CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]
236 where width = typeWidth (cmmRegType reg)
239 = panic "PPC.CodeGen.mangleIndexTree: no match"
241 -- -----------------------------------------------------------------------------
242 -- Code gen for 64-bit arithmetic on 32-bit platforms
245 Simple support for generating 64-bit code (ie, 64 bit values and 64
246 bit assignments) on 32-bit platforms. Unlike the main code generator
247 we merely shoot for generating working code as simply as possible, and
248 pay little attention to code quality. Specifically, there is no
249 attempt to deal cleverly with the fixed-vs-floating register
250 distinction; all values are generated into (pairs of) floating
251 registers, even if this would mean some redundant reg-reg moves as a
252 result. Only one of the VRegUniques is returned, since it will be
253 of the VRegUniqueLo form, and the upper-half VReg can be determined
254 by applying getHiVRegFromLo to it.
257 data ChildCode64 -- a.k.a "Register64"
260 Reg -- the lower 32-bit temporary which contains the
261 -- result; use getHiVRegFromLo to find the other
262 -- VRegUnique. Rules of this simplified insn
263 -- selection game are therefore that the returned
264 -- Reg may be modified
267 -- | The dual to getAnyReg: compute an expression into a register, but
268 -- we don't mind which one it is.
269 getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)
271 r <- getRegister expr
274 tmp <- getNewRegNat rep
275 return (tmp, code tmp)
279 getI64Amodes :: CmmExpr -> NatM (AddrMode, AddrMode, InstrBlock)
280 getI64Amodes addrTree = do
281 Amode hi_addr addr_code <- getAmode addrTree
282 case addrOffset hi_addr 4 of
283 Just lo_addr -> return (hi_addr, lo_addr, addr_code)
284 Nothing -> do (hi_ptr, code) <- getSomeReg addrTree
285 return (AddrRegImm hi_ptr (ImmInt 0),
286 AddrRegImm hi_ptr (ImmInt 4),
290 assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock
291 assignMem_I64Code addrTree valueTree = do
292 (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
293 ChildCode64 vcode rlo <- iselExpr64 valueTree
295 rhi = getHiVRegFromLo rlo
298 mov_hi = ST II32 rhi hi_addr
299 mov_lo = ST II32 rlo lo_addr
301 return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
304 assignReg_I64Code :: CmmReg -> CmmExpr -> NatM InstrBlock
305 assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
306 ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
308 r_dst_lo = mkVReg u_dst II32
309 r_dst_hi = getHiVRegFromLo r_dst_lo
310 r_src_hi = getHiVRegFromLo r_src_lo
311 mov_lo = MR r_dst_lo r_src_lo
312 mov_hi = MR r_dst_hi r_src_hi
315 vcode `snocOL` mov_lo `snocOL` mov_hi
318 assignReg_I64Code lvalue valueTree
319 = panic "assignReg_I64Code(powerpc): invalid lvalue"
322 iselExpr64 :: CmmExpr -> NatM ChildCode64
323 iselExpr64 (CmmLoad addrTree ty) | isWord64 ty = do
324 (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
325 (rlo, rhi) <- getNewRegPairNat II32
326 let mov_hi = LD II32 rhi hi_addr
327 mov_lo = LD II32 rlo lo_addr
328 return $ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi)
331 iselExpr64 (CmmReg (CmmLocal (LocalReg vu ty))) | isWord64 ty
332 = return (ChildCode64 nilOL (mkVReg vu II32))
334 iselExpr64 (CmmLit (CmmInt i _)) = do
335 (rlo,rhi) <- getNewRegPairNat II32
337 half0 = fromIntegral (fromIntegral i :: Word16)
338 half1 = fromIntegral ((fromIntegral i `shiftR` 16) :: Word16)
339 half2 = fromIntegral ((fromIntegral i `shiftR` 32) :: Word16)
340 half3 = fromIntegral ((fromIntegral i `shiftR` 48) :: Word16)
343 LIS rlo (ImmInt half1),
344 OR rlo rlo (RIImm $ ImmInt half0),
345 LIS rhi (ImmInt half3),
346 OR rlo rlo (RIImm $ ImmInt half2)
349 return (ChildCode64 code rlo)
351 iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
352 ChildCode64 code1 r1lo <- iselExpr64 e1
353 ChildCode64 code2 r2lo <- iselExpr64 e2
354 (rlo,rhi) <- getNewRegPairNat II32
356 r1hi = getHiVRegFromLo r1lo
357 r2hi = getHiVRegFromLo r2lo
360 toOL [ ADDC rlo r1lo r2lo,
363 return (ChildCode64 code rlo)
365 iselExpr64 (CmmMachOp (MO_UU_Conv W32 W64) [expr]) = do
366 (expr_reg,expr_code) <- getSomeReg expr
367 (rlo, rhi) <- getNewRegPairNat II32
368 let mov_hi = LI rhi (ImmInt 0)
369 mov_lo = MR rlo expr_reg
370 return $ ChildCode64 (expr_code `snocOL` mov_lo `snocOL` mov_hi)
373 = pprPanic "iselExpr64(powerpc)" (ppr expr)
377 getRegister :: CmmExpr -> NatM Register
379 getRegister (CmmReg reg)
380 = return (Fixed (cmmTypeSize (cmmRegType reg))
381 (getRegisterReg reg) nilOL)
383 getRegister tree@(CmmRegOff _ _)
384 = getRegister (mangleIndexTree tree)
387 #if WORD_SIZE_IN_BITS==32
388 -- for 32-bit architectuers, support some 64 -> 32 bit conversions:
389 -- TO_W_(x), TO_W_(x >> 32)
391 getRegister (CmmMachOp (MO_UU_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_SS_Conv W64 W32)
397 [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]]) = do
398 ChildCode64 code rlo <- iselExpr64 x
399 return $ Fixed II32 (getHiVRegFromLo rlo) code
401 getRegister (CmmMachOp (MO_UU_Conv W64 W32) [x]) = do
402 ChildCode64 code rlo <- iselExpr64 x
403 return $ Fixed II32 rlo code
405 getRegister (CmmMachOp (MO_SS_Conv W64 W32) [x]) = do
406 ChildCode64 code rlo <- iselExpr64 x
407 return $ Fixed II32 rlo code
412 getRegister (CmmLoad mem pk)
415 Amode addr addr_code <- getAmode mem
416 let code dst = ASSERT((regClass dst == RcDouble) == isFloatType pk)
417 addr_code `snocOL` LD size dst addr
418 return (Any size code)
419 where size = cmmTypeSize pk
421 -- catch simple cases of zero- or sign-extended load
422 getRegister (CmmMachOp (MO_UU_Conv W8 W32) [CmmLoad mem _]) = do
423 Amode addr addr_code <- getAmode mem
424 return (Any II32 (\dst -> addr_code `snocOL` LD II8 dst addr))
426 -- Note: there is no Load Byte Arithmetic instruction, so no signed case here
428 getRegister (CmmMachOp (MO_UU_Conv W16 W32) [CmmLoad mem _]) = do
429 Amode addr addr_code <- getAmode mem
430 return (Any II32 (\dst -> addr_code `snocOL` LD II16 dst addr))
432 getRegister (CmmMachOp (MO_SS_Conv W16 W32) [CmmLoad mem _]) = do
433 Amode addr addr_code <- getAmode mem
434 return (Any II32 (\dst -> addr_code `snocOL` LA II16 dst addr))
436 getRegister (CmmMachOp mop [x]) -- unary MachOps
438 MO_Not rep -> triv_ucode_int rep NOT
440 MO_F_Neg w -> triv_ucode_float w FNEG
441 MO_S_Neg w -> triv_ucode_int w NEG
443 MO_FF_Conv W64 W32 -> trivialUCode FF32 FRSP x
444 MO_FF_Conv W32 W64 -> conversionNop FF64 x
446 MO_FS_Conv from to -> coerceFP2Int from to x
447 MO_SF_Conv from to -> coerceInt2FP from to x
450 | from == to -> conversionNop (intSize to) x
452 -- narrowing is a nop: we treat the high bits as undefined
453 MO_SS_Conv W32 to -> conversionNop (intSize to) x
454 MO_SS_Conv W16 W8 -> conversionNop II8 x
455 MO_SS_Conv W8 to -> triv_ucode_int to (EXTS II8)
456 MO_SS_Conv W16 to -> triv_ucode_int to (EXTS II16)
459 | from == to -> conversionNop (intSize to) x
460 -- narrowing is a nop: we treat the high bits as undefined
461 MO_UU_Conv W32 to -> conversionNop (intSize to) x
462 MO_UU_Conv W16 W8 -> conversionNop II8 x
463 MO_UU_Conv W8 to -> trivialCode to False AND x (CmmLit (CmmInt 255 W32))
464 MO_UU_Conv W16 to -> trivialCode to False AND x (CmmLit (CmmInt 65535 W32))
465 _ -> panic "PPC.CodeGen.getRegister: no match"
468 triv_ucode_int width instr = trivialUCode (intSize width) instr x
469 triv_ucode_float width instr = trivialUCode (floatSize width) instr x
471 conversionNop new_size expr
472 = do e_code <- getRegister expr
473 return (swizzleRegisterRep e_code new_size)
475 getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
477 MO_F_Eq w -> condFltReg EQQ x y
478 MO_F_Ne w -> condFltReg NE x y
479 MO_F_Gt w -> condFltReg GTT x y
480 MO_F_Ge w -> condFltReg GE x y
481 MO_F_Lt w -> condFltReg LTT x y
482 MO_F_Le w -> condFltReg LE x y
484 MO_Eq rep -> condIntReg EQQ (extendUExpr rep x) (extendUExpr rep y)
485 MO_Ne rep -> condIntReg NE (extendUExpr rep x) (extendUExpr rep y)
487 MO_S_Gt rep -> condIntReg GTT (extendSExpr rep x) (extendSExpr rep y)
488 MO_S_Ge rep -> condIntReg GE (extendSExpr rep x) (extendSExpr rep y)
489 MO_S_Lt rep -> condIntReg LTT (extendSExpr rep x) (extendSExpr rep y)
490 MO_S_Le rep -> condIntReg LE (extendSExpr rep x) (extendSExpr rep y)
492 MO_U_Gt rep -> condIntReg GU (extendUExpr rep x) (extendUExpr rep y)
493 MO_U_Ge rep -> condIntReg GEU (extendUExpr rep x) (extendUExpr rep y)
494 MO_U_Lt rep -> condIntReg LU (extendUExpr rep x) (extendUExpr rep y)
495 MO_U_Le rep -> condIntReg LEU (extendUExpr rep x) (extendUExpr rep y)
497 MO_F_Add w -> triv_float w FADD
498 MO_F_Sub w -> triv_float w FSUB
499 MO_F_Mul w -> triv_float w FMUL
500 MO_F_Quot w -> triv_float w FDIV
502 -- optimize addition with 32-bit immediate
506 CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate W32 True (-imm)
507 -> trivialCode W32 True ADD x (CmmLit $ CmmInt imm immrep)
510 (src, srcCode) <- getSomeReg x
511 let imm = litToImm lit
512 code dst = srcCode `appOL` toOL [
513 ADDIS dst src (HA imm),
514 ADD dst dst (RIImm (LO imm))
516 return (Any II32 code)
517 _ -> trivialCode W32 True ADD x y
519 MO_Add rep -> trivialCode rep True ADD x y
521 case y of -- subfi ('substract from' with immediate) doesn't exist
522 CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate rep True (-imm)
523 -> trivialCode rep True ADD x (CmmLit $ CmmInt (-imm) immrep)
524 _ -> trivialCodeNoImm' (intSize rep) SUBF y x
526 MO_Mul rep -> trivialCode rep True MULLW x y
528 MO_S_MulMayOflo W32 -> trivialCodeNoImm' II32 MULLW_MayOflo x y
530 MO_S_MulMayOflo rep -> panic "S_MulMayOflo (rep /= II32): not implemented"
531 MO_U_MulMayOflo rep -> panic "U_MulMayOflo: not implemented"
533 MO_S_Quot rep -> trivialCodeNoImm' (intSize rep) DIVW (extendSExpr rep x) (extendSExpr rep y)
534 MO_U_Quot rep -> trivialCodeNoImm' (intSize rep) DIVWU (extendUExpr rep x) (extendUExpr rep y)
536 MO_S_Rem rep -> remainderCode rep DIVW (extendSExpr rep x) (extendSExpr rep y)
537 MO_U_Rem rep -> remainderCode rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
539 MO_And rep -> trivialCode rep False AND x y
540 MO_Or rep -> trivialCode rep False OR x y
541 MO_Xor rep -> trivialCode rep False XOR x y
543 MO_Shl rep -> trivialCode rep False SLW x y
544 MO_S_Shr rep -> trivialCode rep False SRAW (extendSExpr rep x) y
545 MO_U_Shr rep -> trivialCode rep False SRW (extendUExpr rep x) y
546 _ -> panic "PPC.CodeGen.getRegister: no match"
549 triv_float :: Width -> (Size -> Reg -> Reg -> Reg -> Instr) -> NatM Register
550 triv_float width instr = trivialCodeNoImm (floatSize width) instr x y
552 getRegister (CmmLit (CmmInt i rep))
553 | Just imm <- makeImmediate rep True i
555 code dst = unitOL (LI dst imm)
557 return (Any (intSize rep) code)
559 getRegister (CmmLit (CmmFloat f frep)) = do
560 lbl <- getNewLabelNat
561 dflags <- getDynFlagsNat
562 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
563 Amode addr addr_code <- getAmode dynRef
564 let size = floatSize frep
566 LDATA ReadOnlyData [CmmDataLabel lbl,
567 CmmStaticLit (CmmFloat f frep)]
568 `consOL` (addr_code `snocOL` LD size dst addr)
569 return (Any size code)
571 getRegister (CmmLit lit)
572 = let rep = cmmLitType lit
576 ADD dst dst (RIImm (LO imm))
578 in return (Any (cmmTypeSize rep) code)
580 getRegister other = pprPanic "getRegister(ppc)" (pprExpr other)
582 -- extend?Rep: wrap integer expression of type rep
583 -- in a conversion to II32
584 extendSExpr W32 x = x
585 extendSExpr rep x = CmmMachOp (MO_SS_Conv rep W32) [x]
586 extendUExpr W32 x = x
587 extendUExpr rep x = CmmMachOp (MO_UU_Conv rep W32) [x]
589 -- -----------------------------------------------------------------------------
590 -- The 'Amode' type: Memory addressing modes passed up the tree.
593 = Amode AddrMode InstrBlock
596 Now, given a tree (the argument to an CmmLoad) that references memory,
597 produce a suitable addressing mode.
599 A Rule of the Game (tm) for Amodes: use of the addr bit must
600 immediately follow use of the code part, since the code part puts
601 values in registers which the addr then refers to. So you can't put
602 anything in between, lest it overwrite some of those registers. If
603 you need to do some other computation between the code part and use of
604 the addr bit, first store the effective address from the amode in a
605 temporary, then do the other computation, and then use the temporary:
609 ... other computation ...
613 getAmode :: CmmExpr -> NatM Amode
614 getAmode tree@(CmmRegOff _ _) = getAmode (mangleIndexTree tree)
616 getAmode (CmmMachOp (MO_Sub W32) [x, CmmLit (CmmInt i _)])
617 | Just off <- makeImmediate W32 True (-i)
619 (reg, code) <- getSomeReg x
620 return (Amode (AddrRegImm reg off) code)
623 getAmode (CmmMachOp (MO_Add W32) [x, CmmLit (CmmInt i _)])
624 | Just off <- makeImmediate W32 True i
626 (reg, code) <- getSomeReg x
627 return (Amode (AddrRegImm reg off) code)
629 -- optimize addition with 32-bit immediate
631 getAmode (CmmMachOp (MO_Add W32) [x, CmmLit lit])
633 tmp <- getNewRegNat II32
634 (src, srcCode) <- getSomeReg x
635 let imm = litToImm lit
636 code = srcCode `snocOL` ADDIS tmp src (HA imm)
637 return (Amode (AddrRegImm tmp (LO imm)) code)
639 getAmode (CmmLit lit)
641 tmp <- getNewRegNat II32
642 let imm = litToImm lit
643 code = unitOL (LIS tmp (HA imm))
644 return (Amode (AddrRegImm tmp (LO imm)) code)
646 getAmode (CmmMachOp (MO_Add W32) [x, y])
648 (regX, codeX) <- getSomeReg x
649 (regY, codeY) <- getSomeReg y
650 return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))
654 (reg, code) <- getSomeReg other
657 return (Amode (AddrRegImm reg off) code)
661 -- The 'CondCode' type: Condition codes passed up the tree.
663 = CondCode Bool Cond InstrBlock
665 -- Set up a condition code for a conditional branch.
667 getCondCode :: CmmExpr -> NatM CondCode
669 -- almost the same as everywhere else - but we need to
670 -- extend small integers to 32 bit first
672 getCondCode (CmmMachOp mop [x, y])
674 MO_F_Eq W32 -> condFltCode EQQ x y
675 MO_F_Ne W32 -> condFltCode NE x y
676 MO_F_Gt W32 -> condFltCode GTT x y
677 MO_F_Ge W32 -> condFltCode GE x y
678 MO_F_Lt W32 -> condFltCode LTT x y
679 MO_F_Le W32 -> condFltCode LE x y
681 MO_F_Eq W64 -> condFltCode EQQ x y
682 MO_F_Ne W64 -> condFltCode NE x y
683 MO_F_Gt W64 -> condFltCode GTT x y
684 MO_F_Ge W64 -> condFltCode GE x y
685 MO_F_Lt W64 -> condFltCode LTT x y
686 MO_F_Le W64 -> condFltCode LE x y
688 MO_Eq rep -> condIntCode EQQ (extendUExpr rep x) (extendUExpr rep y)
689 MO_Ne rep -> condIntCode NE (extendUExpr rep x) (extendUExpr rep y)
691 MO_S_Gt rep -> condIntCode GTT (extendSExpr rep x) (extendSExpr rep y)
692 MO_S_Ge rep -> condIntCode GE (extendSExpr rep x) (extendSExpr rep y)
693 MO_S_Lt rep -> condIntCode LTT (extendSExpr rep x) (extendSExpr rep y)
694 MO_S_Le rep -> condIntCode LE (extendSExpr rep x) (extendSExpr rep y)
696 MO_U_Gt rep -> condIntCode GU (extendUExpr rep x) (extendUExpr rep y)
697 MO_U_Ge rep -> condIntCode GEU (extendUExpr rep x) (extendUExpr rep y)
698 MO_U_Lt rep -> condIntCode LU (extendUExpr rep x) (extendUExpr rep y)
699 MO_U_Le rep -> condIntCode LEU (extendUExpr rep x) (extendUExpr rep y)
701 other -> pprPanic "getCondCode(powerpc)" (pprMachOp mop)
703 getCondCode other = panic "getCondCode(2)(powerpc)"
707 -- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
708 -- passed back up the tree.
710 condIntCode, condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode
712 -- ###FIXME: I16 and I8!
713 condIntCode cond x (CmmLit (CmmInt y rep))
714 | Just src2 <- makeImmediate rep (not $ condUnsigned cond) y
716 (src1, code) <- getSomeReg x
718 code' = code `snocOL`
719 (if condUnsigned cond then CMPL else CMP) II32 src1 (RIImm src2)
720 return (CondCode False cond code')
722 condIntCode cond x y = do
723 (src1, code1) <- getSomeReg x
724 (src2, code2) <- getSomeReg y
726 code' = code1 `appOL` code2 `snocOL`
727 (if condUnsigned cond then CMPL else CMP) II32 src1 (RIReg src2)
728 return (CondCode False cond code')
730 condFltCode cond x y = do
731 (src1, code1) <- getSomeReg x
732 (src2, code2) <- getSomeReg y
734 code' = code1 `appOL` code2 `snocOL` FCMP src1 src2
735 code'' = case cond of -- twiddle CR to handle unordered case
736 GE -> code' `snocOL` CRNOR ltbit eqbit gtbit
737 LE -> code' `snocOL` CRNOR gtbit eqbit ltbit
740 ltbit = 0 ; eqbit = 2 ; gtbit = 1
741 return (CondCode True cond code'')
745 -- -----------------------------------------------------------------------------
746 -- Generating assignments
748 -- Assignments are really at the heart of the whole code generation
749 -- business. Almost all top-level nodes of any real importance are
750 -- assignments, which correspond to loads, stores, or register
751 -- transfers. If we're really lucky, some of the register transfers
752 -- will go away, because we can use the destination register to
753 -- complete the code generation for the right hand side. This only
754 -- fails when the right hand side is forced into a fixed register
755 -- (e.g. the result of a call).
757 assignMem_IntCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
758 assignReg_IntCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
760 assignMem_FltCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
761 assignReg_FltCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
763 assignMem_IntCode pk addr src = do
764 (srcReg, code) <- getSomeReg src
765 Amode dstAddr addr_code <- getAmode addr
766 return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
768 -- dst is a reg, but src could be anything
769 assignReg_IntCode _ reg src
773 Any _ code -> code dst
774 Fixed _ freg fcode -> fcode `snocOL` MR dst freg
776 dst = getRegisterReg reg
781 assignMem_FltCode = assignMem_IntCode
782 assignReg_FltCode = assignReg_IntCode
786 genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock
788 genJump (CmmLit (CmmLabel lbl))
789 = return (unitOL $ JMP lbl)
793 (target,code) <- getSomeReg tree
794 return (code `snocOL` MTCTR target `snocOL` BCTR [])
797 -- -----------------------------------------------------------------------------
798 -- Unconditional branches
799 genBranch :: BlockId -> NatM InstrBlock
800 genBranch = return . toOL . mkJumpInstr
803 -- -----------------------------------------------------------------------------
807 Conditional jumps are always to local labels, so we can use branch
808 instructions. We peek at the arguments to decide what kind of
811 SPARC: First, we have to ensure that the condition codes are set
812 according to the supplied comparison operation. We generate slightly
813 different code for floating point comparisons, because a floating
814 point operation cannot directly precede a @BF@. We assume the worst
815 and fill that slot with a @NOP@.
817 SPARC: Do not fill the delay slots here; you will confuse the register
823 :: BlockId -- the branch target
824 -> CmmExpr -- the condition on which to branch
827 genCondJump id bool = do
828 CondCode _ cond code <- getCondCode bool
829 return (code `snocOL` BCC cond id)
833 -- -----------------------------------------------------------------------------
834 -- Generating C calls
836 -- Now the biggest nightmare---calls. Most of the nastiness is buried in
837 -- @get_arg@, which moves the arguments to the correct registers/stack
838 -- locations. Apart from that, the code is easy.
840 -- (If applicable) Do not fill the delay slots here; you will confuse the
841 -- register allocator.
844 :: CmmCallTarget -- function to call
845 -> HintedCmmFormals -- where to put the result
846 -> HintedCmmActuals -- arguments (of mixed type)
850 #if darwin_TARGET_OS || linux_TARGET_OS
852 The PowerPC calling convention for Darwin/Mac OS X
853 is described in Apple's document
854 "Inside Mac OS X - Mach-O Runtime Architecture".
856 PowerPC Linux uses the System V Release 4 Calling Convention
857 for PowerPC. It is described in the
858 "System V Application Binary Interface PowerPC Processor Supplement".
860 Both conventions are similar:
861 Parameters may be passed in general-purpose registers starting at r3, in
862 floating point registers starting at f1, or on the stack.
864 But there are substantial differences:
865 * The number of registers used for parameter passing and the exact set of
866 nonvolatile registers differs (see MachRegs.lhs).
867 * On Darwin, stack space is always reserved for parameters, even if they are
868 passed in registers. The called routine may choose to save parameters from
869 registers to the corresponding space on the stack.
870 * On Darwin, a corresponding amount of GPRs is skipped when a floating point
871 parameter is passed in an FPR.
872 * SysV insists on either passing I64 arguments on the stack, or in two GPRs,
873 starting with an odd-numbered GPR. It may skip a GPR to achieve this.
874 Darwin just treats an I64 like two separate II32s (high word first).
875 * I64 and FF64 arguments are 8-byte aligned on the stack for SysV, but only
876 4-byte aligned like everything else on Darwin.
877 * The SysV spec claims that FF32 is represented as FF64 on the stack. GCC on
878 PowerPC Linux does not agree, so neither do we.
880 According to both conventions, The parameter area should be part of the
881 caller's stack frame, allocated in the caller's prologue code (large enough
882 to hold the parameter lists for all called routines). The NCG already
883 uses the stack for register spilling, leaving 64 bytes free at the top.
884 If we need a larger parameter area than that, we just allocate a new stack
885 frame just before ccalling.
889 genCCall (CmmPrim MO_WriteBarrier) _ _
890 = return $ unitOL LWSYNC
892 genCCall target dest_regs argsAndHints
893 = ASSERT (not $ any (`elem` [II8,II16]) $ map cmmTypeSize argReps)
894 -- we rely on argument promotion in the codeGen
896 (finalStack,passArgumentsCode,usedRegs) <- passArguments
898 allArgRegs allFPArgRegs
902 (labelOrExpr, reduceToFF32) <- case target of
903 CmmCallee (CmmLit (CmmLabel lbl)) conv -> return (Left lbl, False)
904 CmmCallee expr conv -> return (Right expr, False)
905 CmmPrim mop -> outOfLineFloatOp mop
907 let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
908 codeAfter = move_sp_up finalStack `appOL` moveResult reduceToFF32
913 `snocOL` BL lbl usedRegs
916 (dynReg, dynCode) <- getSomeReg dyn
918 `snocOL` MTCTR dynReg
920 `snocOL` BCTRL usedRegs
924 initialStackOffset = 24
925 -- size of linkage area + size of arguments, in bytes
926 stackDelta _finalStack = roundTo 16 $ (24 +) $ max 32 $ sum $
927 map (widthInBytes . typeWidth) argReps
928 #elif linux_TARGET_OS
929 initialStackOffset = 8
930 stackDelta finalStack = roundTo 16 finalStack
932 args = map hintlessCmm argsAndHints
933 argReps = map cmmExprType args
935 roundTo a x | x `mod` a == 0 = x
936 | otherwise = x + a - (x `mod` a)
938 move_sp_down finalStack
940 toOL [STU II32 sp (AddrRegImm sp (ImmInt (-delta))),
943 where delta = stackDelta finalStack
944 move_sp_up finalStack
946 toOL [ADD sp sp (RIImm (ImmInt delta)),
949 where delta = stackDelta finalStack
952 passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)
953 passArguments ((arg,arg_ty):args) gprs fprs stackOffset
954 accumCode accumUsed | isWord64 arg_ty =
956 ChildCode64 code vr_lo <- iselExpr64 arg
957 let vr_hi = getHiVRegFromLo vr_lo
964 (accumCode `appOL` code
965 `snocOL` storeWord vr_hi gprs stackOffset
966 `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))
967 ((take 2 gprs) ++ accumUsed)
969 storeWord vr (gpr:_) offset = MR gpr vr
970 storeWord vr [] offset = ST II32 vr (AddrRegImm sp (ImmInt offset))
972 #elif linux_TARGET_OS
973 let stackOffset' = roundTo 8 stackOffset
974 stackCode = accumCode `appOL` code
975 `snocOL` ST II32 vr_hi (AddrRegImm sp (ImmInt stackOffset'))
976 `snocOL` ST II32 vr_lo (AddrRegImm sp (ImmInt (stackOffset'+4)))
977 regCode hireg loreg =
978 accumCode `appOL` code
979 `snocOL` MR hireg vr_hi
980 `snocOL` MR loreg vr_lo
983 hireg : loreg : regs | even (length gprs) ->
984 passArguments args regs fprs stackOffset
985 (regCode hireg loreg) (hireg : loreg : accumUsed)
986 _skipped : hireg : loreg : regs ->
987 passArguments args regs fprs stackOffset
988 (regCode hireg loreg) (hireg : loreg : accumUsed)
989 _ -> -- only one or no regs left
990 passArguments args [] fprs (stackOffset'+8)
994 passArguments ((arg,rep):args) gprs fprs stackOffset accumCode accumUsed
995 | reg : _ <- regs = do
996 register <- getRegister arg
997 let code = case register of
998 Fixed _ freg fcode -> fcode `snocOL` MR reg freg
999 Any _ acode -> acode reg
1003 #if darwin_TARGET_OS
1004 -- The Darwin ABI requires that we reserve stack slots for register parameters
1005 (stackOffset + stackBytes)
1006 #elif linux_TARGET_OS
1007 -- ... the SysV ABI doesn't.
1010 (accumCode `appOL` code)
1013 (vr, code) <- getSomeReg arg
1017 (stackOffset' + stackBytes)
1018 (accumCode `appOL` code `snocOL` ST (cmmTypeSize rep) vr stackSlot)
1021 #if darwin_TARGET_OS
1022 -- stackOffset is at least 4-byte aligned
1023 -- The Darwin ABI is happy with that.
1024 stackOffset' = stackOffset
1026 -- ... the SysV ABI requires 8-byte alignment for doubles.
1027 stackOffset' | isFloatType rep && typeWidth rep == W64 =
1028 roundTo 8 stackOffset
1029 | otherwise = stackOffset
1031 stackSlot = AddrRegImm sp (ImmInt stackOffset')
1032 (nGprs, nFprs, stackBytes, regs) = case cmmTypeSize rep of
1033 II32 -> (1, 0, 4, gprs)
1034 #if darwin_TARGET_OS
1035 -- The Darwin ABI requires that we skip a corresponding number of GPRs when
1037 FF32 -> (1, 1, 4, fprs)
1038 FF64 -> (2, 1, 8, fprs)
1039 #elif linux_TARGET_OS
1040 -- ... the SysV ABI doesn't.
1041 FF32 -> (0, 1, 4, fprs)
1042 FF64 -> (0, 1, 8, fprs)
1045 moveResult reduceToFF32 =
1048 [CmmHinted dest _hint]
1049 | reduceToFF32 && isFloat32 rep -> unitOL (FRSP r_dest f1)
1050 | isFloat32 rep || isFloat64 rep -> unitOL (MR r_dest f1)
1051 | isWord64 rep -> toOL [MR (getHiVRegFromLo r_dest) r3,
1053 | otherwise -> unitOL (MR r_dest r3)
1054 where rep = cmmRegType (CmmLocal dest)
1055 r_dest = getRegisterReg (CmmLocal dest)
1057 outOfLineFloatOp mop =
1059 dflags <- getDynFlagsNat
1060 mopExpr <- cmmMakeDynamicReference dflags addImportNat CallReference $
1061 mkForeignLabel functionName Nothing True IsFunction
1062 let mopLabelOrExpr = case mopExpr of
1063 CmmLit (CmmLabel lbl) -> Left lbl
1065 return (mopLabelOrExpr, reduce)
1067 (functionName, reduce) = case mop of
1068 MO_F32_Exp -> (fsLit "exp", True)
1069 MO_F32_Log -> (fsLit "log", True)
1070 MO_F32_Sqrt -> (fsLit "sqrt", True)
1072 MO_F32_Sin -> (fsLit "sin", True)
1073 MO_F32_Cos -> (fsLit "cos", True)
1074 MO_F32_Tan -> (fsLit "tan", True)
1076 MO_F32_Asin -> (fsLit "asin", True)
1077 MO_F32_Acos -> (fsLit "acos", True)
1078 MO_F32_Atan -> (fsLit "atan", True)
1080 MO_F32_Sinh -> (fsLit "sinh", True)
1081 MO_F32_Cosh -> (fsLit "cosh", True)
1082 MO_F32_Tanh -> (fsLit "tanh", True)
1083 MO_F32_Pwr -> (fsLit "pow", True)
1085 MO_F64_Exp -> (fsLit "exp", False)
1086 MO_F64_Log -> (fsLit "log", False)
1087 MO_F64_Sqrt -> (fsLit "sqrt", False)
1089 MO_F64_Sin -> (fsLit "sin", False)
1090 MO_F64_Cos -> (fsLit "cos", False)
1091 MO_F64_Tan -> (fsLit "tan", False)
1093 MO_F64_Asin -> (fsLit "asin", False)
1094 MO_F64_Acos -> (fsLit "acos", False)
1095 MO_F64_Atan -> (fsLit "atan", False)
1097 MO_F64_Sinh -> (fsLit "sinh", False)
1098 MO_F64_Cosh -> (fsLit "cosh", False)
1099 MO_F64_Tanh -> (fsLit "tanh", False)
1100 MO_F64_Pwr -> (fsLit "pow", False)
1101 other -> pprPanic "genCCall(ppc): unknown callish op"
1102 (pprCallishMachOp other)
1104 #else /* darwin_TARGET_OS || linux_TARGET_OS */
1105 genCCall = panic "PPC.CodeGen.genCCall: not defined for this os"
1109 -- -----------------------------------------------------------------------------
1110 -- Generating a table-branch
1112 genSwitch :: CmmExpr -> [Maybe BlockId] -> NatM InstrBlock
1116 (reg,e_code) <- getSomeReg expr
1117 tmp <- getNewRegNat II32
1118 lbl <- getNewLabelNat
1119 dflags <- getDynFlagsNat
1120 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
1121 (tableReg,t_code) <- getSomeReg $ dynRef
1123 jumpTable = map jumpTableEntryRel ids
1125 jumpTableEntryRel Nothing
1126 = CmmStaticLit (CmmInt 0 wordWidth)
1127 jumpTableEntryRel (Just (BlockId id))
1128 = CmmStaticLit (CmmLabelDiffOff blockLabel lbl 0)
1129 where blockLabel = mkAsmTempLabel id
1131 code = e_code `appOL` t_code `appOL` toOL [
1132 LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
1133 SLW tmp reg (RIImm (ImmInt 2)),
1134 LD II32 tmp (AddrRegReg tableReg tmp),
1135 ADD tmp tmp (RIReg tableReg),
1137 BCTR [ id | Just id <- ids ]
1142 (reg,e_code) <- getSomeReg expr
1143 tmp <- getNewRegNat II32
1144 lbl <- getNewLabelNat
1146 jumpTable = map jumpTableEntry ids
1148 code = e_code `appOL` toOL [
1149 LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
1150 SLW tmp reg (RIImm (ImmInt 2)),
1151 ADDIS tmp tmp (HA (ImmCLbl lbl)),
1152 LD II32 tmp (AddrRegImm tmp (LO (ImmCLbl lbl))),
1154 BCTR [ id | Just id <- ids ]
1159 -- -----------------------------------------------------------------------------
1160 -- 'condIntReg' and 'condFltReg': condition codes into registers
1162 -- Turn those condition codes into integers now (when they appear on
1163 -- the right hand side of an assignment).
1165 -- (If applicable) Do not fill the delay slots here; you will confuse the
1166 -- register allocator.
1168 condIntReg, condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register
1170 condReg :: NatM CondCode -> NatM Register
1171 condReg getCond = do
1172 CondCode _ cond cond_code <- getCond
1174 {- code dst = cond_code `appOL` toOL [
1183 code dst = cond_code
1187 RLWINM dst dst (bit + 1) 31 31
1190 negate_code | do_negate = unitOL (CRNOR bit bit bit)
1193 (bit, do_negate) = case cond of
1206 _ -> panic "PPC.CodeGen.codeReg: no match"
1208 return (Any II32 code)
1210 condIntReg cond x y = condReg (condIntCode cond x y)
1211 condFltReg cond x y = condReg (condFltCode cond x y)
1215 -- -----------------------------------------------------------------------------
1216 -- 'trivial*Code': deal with trivial instructions
1218 -- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',
1219 -- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.
1220 -- Only look for constants on the right hand side, because that's
1221 -- where the generic optimizer will have put them.
1223 -- Similarly, for unary instructions, we don't have to worry about
1224 -- matching an StInt as the argument, because genericOpt will already
1225 -- have handled the constant-folding.
1230 Wolfgang's PowerPC version of The Rules:
1232 A slightly modified version of The Rules to take advantage of the fact
1233 that PowerPC instructions work on all registers and don't implicitly
1234 clobber any fixed registers.
1236 * The only expression for which getRegister returns Fixed is (CmmReg reg).
1238 * If getRegister returns Any, then the code it generates may modify only:
1239 (a) fresh temporaries
1240 (b) the destination register
1241 It may *not* modify global registers, unless the global
1242 register happens to be the destination register.
1243 It may not clobber any other registers. In fact, only ccalls clobber any
1245 Also, it may not modify the counter register (used by genCCall).
1247 Corollary: If a getRegister for a subexpression returns Fixed, you need
1248 not move it to a fresh temporary before evaluating the next subexpression.
1249 The Fixed register won't be modified.
1250 Therefore, we don't need a counterpart for the x86's getStableReg on PPC.
1252 * SDM's First Rule is valid for PowerPC, too: subexpressions can depend on
1253 the value of the destination register.
1259 -> (Reg -> Reg -> RI -> Instr)
1264 trivialCode rep signed instr x (CmmLit (CmmInt y _))
1265 | Just imm <- makeImmediate rep signed y
1267 (src1, code1) <- getSomeReg x
1268 let code dst = code1 `snocOL` instr dst src1 (RIImm imm)
1269 return (Any (intSize rep) code)
1271 trivialCode rep _ instr x y = do
1272 (src1, code1) <- getSomeReg x
1273 (src2, code2) <- getSomeReg y
1274 let code dst = code1 `appOL` code2 `snocOL` instr dst src1 (RIReg src2)
1275 return (Any (intSize rep) code)
1277 trivialCodeNoImm' :: Size -> (Reg -> Reg -> Reg -> Instr)
1278 -> CmmExpr -> CmmExpr -> NatM Register
1279 trivialCodeNoImm' size instr x y = do
1280 (src1, code1) <- getSomeReg x
1281 (src2, code2) <- getSomeReg y
1282 let code dst = code1 `appOL` code2 `snocOL` instr dst src1 src2
1283 return (Any size code)
1285 trivialCodeNoImm :: Size -> (Size -> Reg -> Reg -> Reg -> Instr)
1286 -> CmmExpr -> CmmExpr -> NatM Register
1287 trivialCodeNoImm size instr x y = trivialCodeNoImm' size (instr size) x y
1292 -> (Reg -> Reg -> Instr)
1295 trivialUCode rep instr x = do
1296 (src, code) <- getSomeReg x
1297 let code' dst = code `snocOL` instr dst src
1298 return (Any rep code')
1300 -- There is no "remainder" instruction on the PPC, so we have to do
1302 -- The "div" parameter is the division instruction to use (DIVW or DIVWU)
1304 remainderCode :: Width -> (Reg -> Reg -> Reg -> Instr)
1305 -> CmmExpr -> CmmExpr -> NatM Register
1306 remainderCode rep div x y = do
1307 (src1, code1) <- getSomeReg x
1308 (src2, code2) <- getSomeReg y
1309 let code dst = code1 `appOL` code2 `appOL` toOL [
1311 MULLW dst dst (RIReg src2),
1314 return (Any (intSize rep) code)
1317 coerceInt2FP :: Width -> Width -> CmmExpr -> NatM Register
1318 coerceInt2FP fromRep toRep x = do
1319 (src, code) <- getSomeReg x
1320 lbl <- getNewLabelNat
1321 itmp <- getNewRegNat II32
1322 ftmp <- getNewRegNat FF64
1323 dflags <- getDynFlagsNat
1324 dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
1325 Amode addr addr_code <- getAmode dynRef
1327 code' dst = code `appOL` maybe_exts `appOL` toOL [
1330 CmmStaticLit (CmmInt 0x43300000 W32),
1331 CmmStaticLit (CmmInt 0x80000000 W32)],
1332 XORIS itmp src (ImmInt 0x8000),
1333 ST II32 itmp (spRel 3),
1334 LIS itmp (ImmInt 0x4330),
1335 ST II32 itmp (spRel 2),
1336 LD FF64 ftmp (spRel 2)
1337 ] `appOL` addr_code `appOL` toOL [
1339 FSUB FF64 dst ftmp dst
1340 ] `appOL` maybe_frsp dst
1342 maybe_exts = case fromRep of
1343 W8 -> unitOL $ EXTS II8 src src
1344 W16 -> unitOL $ EXTS II16 src src
1346 _ -> panic "PPC.CodeGen.coerceInt2FP: no match"
1350 W32 -> unitOL $ FRSP dst dst
1352 _ -> panic "PPC.CodeGen.coerceInt2FP: no match"
1354 return (Any (floatSize toRep) code')
1356 coerceFP2Int :: Width -> Width -> CmmExpr -> NatM Register
1357 coerceFP2Int _ toRep x = do
1358 -- the reps don't really matter: F*->FF64 and II32->I* are no-ops
1359 (src, code) <- getSomeReg x
1360 tmp <- getNewRegNat FF64
1362 code' dst = code `appOL` toOL [
1363 -- convert to int in FP reg
1365 -- store value (64bit) from FP to stack
1366 ST FF64 tmp (spRel 2),
1367 -- read low word of value (high word is undefined)
1368 LD II32 dst (spRel 3)]
1369 return (Any (intSize toRep) code')