+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
-----------------------------------------------------------------------------
--
-- Generating machine code (instruction selection)
import Pretty
import Outputable
import FastString
-import FastTypes ( isFastTrue )
+import FastBool ( isFastTrue )
import Constants ( wORD_SIZE )
#ifdef DEBUG
+import Outputable ( assertPanic )
import Debug.Trace ( trace )
#endif
+import Debug.Trace ( trace )
import Control.Monad ( mapAndUnzipM )
import Data.Maybe ( fromJust )
type InstrBlock = OrdList Instr
cmmTopCodeGen :: RawCmmTop -> NatM [NatCmmTop]
-cmmTopCodeGen (CmmProc info lab params blocks) = do
+cmmTopCodeGen (CmmProc info lab params (ListGraph blocks)) = do
(nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
picBaseMb <- getPicBaseMaybeNat
- let proc = CmmProc info lab params (concat nat_blocks)
+ let proc = CmmProc info lab params (ListGraph $ concat nat_blocks)
tops = proc : concat statics
case picBaseMb of
Just picBase -> initializePicBase picBase tops
| otherwise -> assignMem_IntCode kind addr src
where kind = cmmExprRep src
- CmmCall target result_regs args _
+ CmmCall target result_regs args _ _
-> genCCall target result_regs args
CmmBranch id -> genBranch id
mov_lo = ST I32 rlo (AddrRegImm src (ImmInt 4))
return (vcode `appOL` code `snocOL` mov_hi `snocOL` mov_lo)
-assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
+assignReg_I64Code (CmmLocal (LocalReg u_dst pk _)) valueTree = do
ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
let
r_dst_lo = mkVReg u_dst pk
rlo
)
-iselExpr64 (CmmReg (CmmLocal (LocalReg uq I64))) = do
+iselExpr64 (CmmReg (CmmLocal (LocalReg uq I64 _))) = do
r_dst_lo <- getNewRegNat I32
let r_dst_hi = getHiVRegFromLo r_dst_lo
r_src_lo = mkVReg uq I32
-- in
return (ChildCode64 code rlo)
+iselExpr64 (CmmMachOp (MO_U_Conv I32 I64) [expr]) = do
+ (expr_reg,expr_code) <- getSomeReg expr
+ (rlo, rhi) <- getNewRegPairNat I32
+ let mov_hi = LI rhi (ImmInt 0)
+ mov_lo = MR rlo expr_reg
+ return $ ChildCode64 (expr_code `snocOL` mov_lo `snocOL` mov_hi)
+ rlo
iselExpr64 expr
= pprPanic "iselExpr64(powerpc)" (ppr expr)
getRegister (CmmLit (CmmFloat f F32)) = do
lbl <- getNewLabelNat
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
Amode addr addr_code <- getAmode dynRef
let code dst =
LDATA ReadOnlyData
| otherwise = do
lbl <- getNewLabelNat
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
Amode addr addr_code <- getAmode dynRef
let code dst =
LDATA ReadOnlyData
getRegister e@(CmmMachOp mop [x, y]) -- dyadic MachOps
- = ASSERT2(cmmExprRep x /= I8, pprExpr e)
- case mop of
+ = case mop of
MO_Eq F32 -> condFltReg EQQ x y
MO_Ne F32 -> condFltReg NE x y
MO_S_Gt F32 -> condFltReg GTT x y
getRegister (CmmLit (CmmFloat f frep)) = do
lbl <- getNewLabelNat
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
Amode addr addr_code <- getAmode dynRef
let code dst =
LDATA ReadOnlyData [CmmDataLabel lbl,
= let rep = cmmLitRep lit
imm = litToImm lit
code dst = toOL [
- LIS dst (HI imm),
- OR dst dst (RIImm (LO imm))
+ LIS dst (HA imm),
+ ADD dst dst (RIImm (LO imm))
]
in return (Any rep code)
--
return (CondCode False cond code)
+-- anything vs zero, using a mask
+-- TODO: Add some sanity checking!!!!
+condIntCode cond (CmmMachOp (MO_And rep) [x,o2]) (CmmLit (CmmInt 0 pk))
+ | (CmmLit (CmmInt mask pk2)) <- o2
+ = do
+ (x_reg, x_code) <- getSomeReg x
+ let
+ code = x_code `snocOL`
+ TEST pk (OpImm (ImmInteger mask)) (OpReg x_reg)
+ --
+ return (CondCode False cond code)
+
-- anything vs zero
condIntCode cond x (CmmLit (CmmInt 0 pk)) = do
(x_reg, x_code) <- getSomeReg x
genCCall
:: CmmCallTarget -- function to call
- -> CmmHintFormals -- where to put the result
+ -> CmmFormals -- where to put the result
-> CmmActuals -- arguments (of mixed type)
-> NatM InstrBlock
-- we keep it this long in order to prevent earlier optimisations.
-- we only cope with a single result for foreign calls
-genCCall (CmmPrim op) [(r,_)] args = do
+genCCall (CmmPrim op) [CmmHinted r _] args = do
case op of
MO_F32_Sqrt -> actuallyInlineFloatOp F32 (GSQRT F32) args
MO_F64_Sqrt -> actuallyInlineFloatOp F64 (GSQRT F64) args
other_op -> outOfLineFloatOp op r args
where
- actuallyInlineFloatOp rep instr [(x,_)]
+ actuallyInlineFloatOp rep instr [CmmHinted x _]
= do res <- trivialUFCode rep instr x
any <- anyReg res
return (any (getRegisterReg (CmmLocal r)))
genCCall target dest_regs args = do
let
- sizes = map (arg_size . cmmExprRep . fst) (reverse args)
+ sizes = map (arg_size . cmmExprRep . hintlessCmm) (reverse args)
#if !darwin_TARGET_OS
tot_arg_size = sum sizes
#else
(callinsns,cconv) <-
case target of
-- CmmPrim -> ...
- CmmForeignCall (CmmLit (CmmLabel lbl)) conv
+ CmmCallee (CmmLit (CmmLabel lbl)) conv
-> -- ToDo: stdcall arg sizes
return (unitOL (CALL (Left fn_imm) []), conv)
where fn_imm = ImmCLbl lbl
- CmmForeignCall expr conv
+ CmmCallee expr conv
-> do (dyn_c, dyn_r, dyn_rep) <- get_op expr
ASSERT(dyn_rep == I32)
return (dyn_c `snocOL` CALL (Right dyn_r) [], conv)
let
-- assign the results, if necessary
assign_code [] = nilOL
- assign_code [(dest,_hint)] =
+ assign_code [CmmHinted dest _hint] =
case rep of
I64 -> toOL [MOV I32 (OpReg eax) (OpReg r_dest),
MOV I32 (OpReg edx) (OpReg r_dest_hi)]
| otherwise = x + a - (x `mod` a)
- push_arg :: (CmmExpr,MachHint){-current argument-}
+ push_arg :: (CmmHinted CmmExpr){-current argument-}
-> NatM InstrBlock -- code
- push_arg (arg,_hint) -- we don't need the hints on x86
+ push_arg (CmmHinted arg _hint) -- we don't need the hints on x86
| arg_rep == I64 = do
ChildCode64 code r_lo <- iselExpr64 arg
delta <- getDeltaNat
#if i386_TARGET_ARCH || x86_64_TARGET_ARCH
-outOfLineFloatOp :: CallishMachOp -> CmmFormal -> CmmActuals
+outOfLineFloatOp :: CallishMachOp -> CmmFormalWithoutKind -> CmmActuals
-> NatM InstrBlock
outOfLineFloatOp mop res args
= do
- targetExpr <- cmmMakeDynamicReference addImportNat CallReference lbl
- let target = CmmForeignCall targetExpr CCallConv
+ dflags <- getDynFlagsNat
+ targetExpr <- cmmMakeDynamicReference dflags addImportNat CallReference lbl
+ let target = CmmCallee targetExpr CCallConv
if localRegRep res == F64
then
- stmtToInstrs (CmmCall target [(res,FloatHint)] args CmmUnsafe)
+ stmtToInstrs (CmmCall target [CmmHinted res FloatHint] args CmmUnsafe CmmMayReturn)
else do
uq <- getUniqueNat
let
- tmp = LocalReg uq F64 KindNonPtr
+ tmp = LocalReg uq F64 GCKindNonPtr
-- in
- code1 <- stmtToInstrs (CmmCall target [(tmp,FloatHint)] args CmmUnsafe)
+ code1 <- stmtToInstrs (CmmCall target [CmmHinted tmp FloatHint] args CmmUnsafe CmmMayReturn)
code2 <- stmtToInstrs (CmmAssign (CmmLocal res) (CmmReg (CmmLocal tmp)))
return (code1 `appOL` code2)
where
-- write barrier compiles to no code on x86/x86-64;
-- we keep it this long in order to prevent earlier optimisations.
-genCCall (CmmPrim op) [(r,_)] args =
+
+genCCall (CmmPrim op) [CmmHinted r _] args =
outOfLineFloatOp op r args
genCCall target dest_regs args = do
(callinsns,cconv) <-
case target of
-- CmmPrim -> ...
- CmmForeignCall (CmmLit (CmmLabel lbl)) conv
+ CmmCallee (CmmLit (CmmLabel lbl)) conv
-> -- ToDo: stdcall arg sizes
return (unitOL (CALL (Left fn_imm) arg_regs), conv)
where fn_imm = ImmCLbl lbl
- CmmForeignCall expr conv
+ CmmCallee expr conv
-> do (dyn_r, dyn_c) <- getSomeReg expr
return (dyn_c `snocOL` CALL (Right dyn_r) arg_regs, conv)
let
-- assign the results, if necessary
assign_code [] = nilOL
- assign_code [(dest,_hint)] =
+ assign_code [CmmHinted dest _hint] =
case rep of
F32 -> unitOL (MOV rep (OpReg xmm0) (OpReg r_dest))
F64 -> unitOL (MOV rep (OpReg xmm0) (OpReg r_dest))
where
arg_size = 8 -- always, at the mo
- load_args :: [(CmmExpr,MachHint)]
+ load_args :: [CmmHinted CmmExpr]
-> [Reg] -- int regs avail for args
-> [Reg] -- FP regs avail for args
-> InstrBlock
- -> NatM ([(CmmExpr,MachHint)],[Reg],[Reg],InstrBlock)
+ -> NatM ([CmmHinted CmmExpr],[Reg],[Reg],InstrBlock)
load_args args [] [] code = return (args, [], [], code)
-- no more regs to use
load_args [] aregs fregs code = return ([], aregs, fregs, code)
-- no more args to push
- load_args ((arg,hint) : rest) aregs fregs code
+ load_args ((CmmHinted arg hint) : rest) aregs fregs code
| isFloatingRep arg_rep =
case fregs of
[] -> push_this_arg
push_this_arg = do
(args',ars,frs,code') <- load_args rest aregs fregs code
- return ((arg,hint):args', ars, frs, code')
+ return ((CmmHinted arg hint):args', ars, frs, code')
push_args [] code = return code
- push_args ((arg,hint):rest) code
+ push_args ((CmmHinted arg hint):rest) code
| isFloatingRep arg_rep = do
(arg_reg, arg_code) <- getSomeReg arg
delta <- getDeltaNat
genCCall target dest_regs argsAndHints = do
let
- args = map fst argsAndHints
+ args = map hintlessCmm argsAndHints
argcode_and_vregs <- mapM arg_to_int_vregs args
let
(argcodes, vregss) = unzip argcode_and_vregs
vregs = concat vregss
-- deal with static vs dynamic call targets
callinsns <- (case target of
- CmmForeignCall (CmmLit (CmmLabel lbl)) conv -> do
+ CmmCallee (CmmLit (CmmLabel lbl)) conv -> do
return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))
- CmmForeignCall expr conv -> do
+ CmmCallee expr conv -> do
(dyn_c, [dyn_r]) <- arg_to_int_vregs expr
return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
CmmPrim mop -> do
)
outOfLineFloatOp mop =
do
- mopExpr <- cmmMakeDynamicReference addImportNat CallReference $
+ dflags <- getDynFlagsNat
+ mopExpr <- cmmMakeDynamicReference dflags addImportNat CallReference $
mkForeignLabel functionName Nothing True
let mopLabelOrExpr = case mopExpr of
CmmLit (CmmLabel lbl) -> Left lbl
(toOL []) []
(labelOrExpr, reduceToF32) <- case target of
- CmmForeignCall (CmmLit (CmmLabel lbl)) conv -> return (Left lbl, False)
- CmmForeignCall expr conv -> return (Right expr, False)
+ CmmCallee (CmmLit (CmmLabel lbl)) conv -> return (Left lbl, False)
+ CmmCallee expr conv -> return (Right expr, False)
CmmPrim mop -> outOfLineFloatOp mop
let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
initialStackOffset = 8
stackDelta finalStack = roundTo 16 finalStack
#endif
- args = map fst argsAndHints
+ args = map hintlessCmm argsAndHints
argReps = map cmmExprRep args
roundTo a x | x `mod` a == 0 = x
moveResult reduceToF32 =
case dest_regs of
[] -> nilOL
- [(dest, _hint)]
+ [CmmHinted dest _hint]
| reduceToF32 && rep == F32 -> unitOL (FRSP r_dest f1)
| rep == F32 || rep == F64 -> unitOL (MR r_dest f1)
| rep == I64 -> toOL [MR (getHiVRegFromLo r_dest) r3,
outOfLineFloatOp mop =
do
- mopExpr <- cmmMakeDynamicReference addImportNat CallReference $
+ dflags <- getDynFlagsNat
+ mopExpr <- cmmMakeDynamicReference dflags addImportNat CallReference $
mkForeignLabel functionName Nothing True
let mopLabelOrExpr = case mopExpr of
CmmLit (CmmLabel lbl) -> Left lbl
= do
(reg,e_code) <- getSomeReg expr
lbl <- getNewLabelNat
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
(tableReg,t_code) <- getSomeReg $ dynRef
let
jumpTable = map jumpTableEntryRel ids
op = OpAddr (AddrBaseIndex (EABaseReg tableReg)
(EAIndex reg wORD_SIZE) (ImmInt 0))
-#if x86_64_TARGET_ARCH && darwin_TARGET_OS
+#if x86_64_TARGET_ARCH
+#if darwin_TARGET_OS
-- on Mac OS X/x86_64, put the jump table in the text section
-- to work around a limitation of the linker.
-- ld64 is unable to handle the relocations for
LDATA Text (CmmDataLabel lbl : jumpTable)
]
#else
+ -- HACK: On x86_64 binutils<2.17 is only able to generate PC32
+ -- relocations, hence we only get 32-bit offsets in the jump
+ -- table. As these offsets are always negative we need to properly
+ -- sign extend them to 64-bit. This hack should be removed in
+ -- conjunction with the hack in PprMach.hs/pprDataItem once
+ -- binutils 2.17 is standard.
+ code = e_code `appOL` t_code `appOL` toOL [
+ LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
+ MOVSxL I32
+ (OpAddr (AddrBaseIndex (EABaseReg tableReg)
+ (EAIndex reg wORD_SIZE) (ImmInt 0)))
+ (OpReg reg),
+ ADD wordRep (OpReg reg) (OpReg tableReg),
+ JMP_TBL (OpReg tableReg) [ id | Just id <- ids ]
+ ]
+#endif
+#else
code = e_code `appOL` t_code `appOL` toOL [
LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
ADD wordRep op (OpReg tableReg),
(reg,e_code) <- getSomeReg expr
tmp <- getNewRegNat I32
lbl <- getNewLabelNat
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
(tableReg,t_code) <- getSomeReg $ dynRef
let
jumpTable = map jumpTableEntryRel ids
]
return code
#else
-genSwitch expr ids = panic "ToDo: genSwitch"
+#error "ToDo: genSwitch"
#endif
jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordRep)
lbl <- getNewLabelNat
itmp <- getNewRegNat I32
ftmp <- getNewRegNat F64
- dynRef <- cmmMakeDynamicReference addImportNat DataReference lbl
+ dflags <- getDynFlagsNat
+ dynRef <- cmmMakeDynamicReference dflags addImportNat DataReference lbl
Amode addr addr_code <- getAmode dynRef
let
code' dst = code `appOL` maybe_exts `appOL` toOL [