module GHC.CmmToAsm.AArch64.CodeGen (
cmmTopCodeGen
, generateJumpTableForInstr
)
where
import GHC.Prelude hiding (EQ)
import Data.Word
import GHC.Platform.Regs
import GHC.CmmToAsm.AArch64.Instr
import GHC.CmmToAsm.AArch64.Regs
import GHC.CmmToAsm.AArch64.Cond
import GHC.CmmToAsm.CPrim
import GHC.Cmm.DebugBlock
import GHC.CmmToAsm.Monad
( NatM, getNewRegNat
, getPicBaseMaybeNat, getPlatform, getConfig
, getDebugBlock, getFileId
)
import GHC.CmmToAsm.PIC
import GHC.CmmToAsm.Format
import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Types
import GHC.Platform.Reg
import GHC.Platform
import GHC.Cmm.BlockId
import GHC.Cmm
import GHC.Cmm.Utils
import GHC.Cmm.Switch
import GHC.Cmm.CLabel
import GHC.Cmm.Dataflow.Block
import GHC.Cmm.Dataflow.Graph
import GHC.Types.Tickish ( GenTickish(..) )
import GHC.Types.SrcLoc ( srcSpanFile, srcSpanStartLine, srcSpanStartCol )
import GHC.Data.OrdList
import GHC.Utils.Outputable
import Control.Monad ( mapAndUnzipM, foldM )
import Data.Maybe
import GHC.Float
import GHC.Types.Basic
import GHC.Types.ForeignCall
import GHC.Data.FastString
import GHC.Utils.Misc
import GHC.Utils.Panic
cmmTopCodeGen
:: RawCmmDecl
-> NatM [NatCmmDecl RawCmmStatics Instr]
cmmTopCodeGen _cmm@(CmmProc info lab live graph) = do
let blocks = toBlockListEntryFirst graph
(nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
picBaseMb <- getPicBaseMaybeNat
let proc = CmmProc info lab live (ListGraph $ concat nat_blocks)
tops = proc : concat statics
case picBaseMb of
Just _picBase -> panic "AArch64.cmmTopCodeGen: picBase not implemented"
Nothing -> return tops
cmmTopCodeGen _cmm@(CmmData sec dat) = do
return [CmmData sec dat]
basicBlockCodeGen
:: Block CmmNode C C
-> NatM ( [NatBasicBlock Instr]
, [NatCmmDecl RawCmmStatics Instr])
basicBlockCodeGen block = do
config <- getConfig
let (_, nodes, tail) = blockSplit block
id = entryLabel block
stmts = blockToList nodes
header_comment_instr = unitOL $ MULTILINE_COMMENT (
text "-- --------------------------- basicBlockCodeGen --------------------------- --\n"
$+$ pdoc (ncgPlatform config) block
)
dbg <- getDebugBlock (entryLabel block)
loc_instrs <- case dblSourceTick =<< dbg of
Just (SourceNote span name)
-> do fileId <- getFileId (srcSpanFile span)
let line = srcSpanStartLine span; col = srcSpanStartCol span
return $ unitOL $ LOCATION fileId line col name
_ -> return nilOL
(mid_instrs,mid_bid) <- stmtsToInstrs id stmts
(!tail_instrs,_) <- stmtToInstrs mid_bid tail
let instrs = header_comment_instr `appOL` loc_instrs `appOL` mid_instrs `appOL` tail_instrs
let
(top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs
mkBlocks (NEWBLOCK id) (instrs,blocks,statics)
= ([], BasicBlock id instrs : blocks, statics)
mkBlocks (LDATA sec dat) (instrs,blocks,statics)
= (instrs, blocks, CmmData sec dat:statics)
mkBlocks instr (instrs,blocks,statics)
= (instr:instrs, blocks, statics)
return (BasicBlock id top : other_blocks, statics)
ann :: SDoc -> Instr -> Instr
ann doc instr = ANN doc instr
annExpr :: CmmExpr -> Instr -> Instr
annExpr e instr = ANN (text . show $ e) instr
genSwitch :: CmmExpr -> SwitchTargets -> NatM InstrBlock
genSwitch expr targets = do
(reg, format, code) <- getSomeReg expr
let w = formatToWidth format
let mkbranch acc (key, bid) = do
(keyReg, _format, code) <- getSomeReg (CmmLit (CmmInt key w))
return $ code `appOL`
toOL [ CMP (OpReg w reg) (OpReg w keyReg)
, BCOND EQ (TBlock bid)
] `appOL` acc
def_code = case switchTargetsDefault targets of
Just bid -> unitOL (B (TBlock bid))
Nothing -> nilOL
switch_code <- foldM mkbranch nilOL (switchTargetsCases targets)
return $ code `appOL` switch_code `appOL` def_code
generateJumpTableForInstr :: NCGConfig -> Instr
-> Maybe (NatCmmDecl RawCmmStatics Instr)
generateJumpTableForInstr _ _ = Nothing
stmtsToInstrs :: BlockId
-> [CmmNode O O]
-> NatM (InstrBlock, BlockId)
stmtsToInstrs bid stmts =
go bid stmts nilOL
where
go bid [] instrs = return (instrs,bid)
go bid (s:stmts) instrs = do
(instrs',bid') <- stmtToInstrs bid s
let !newBid = fromMaybe bid bid'
go newBid stmts (instrs `appOL` instrs')
stmtToInstrs :: BlockId
-> CmmNode e x
-> NatM (InstrBlock, Maybe BlockId)
stmtToInstrs bid stmt = do
platform <- getPlatform
case stmt of
CmmUnsafeForeignCall target result_regs args
-> genCCall target result_regs args bid
_ -> (,Nothing) <$> case stmt of
CmmComment s -> return (unitOL (COMMENT (ftext s)))
CmmTick {} -> return nilOL
CmmAssign reg src
| isFloatType ty -> assignReg_FltCode format reg src
| otherwise -> assignReg_IntCode format reg src
where ty = cmmRegType platform reg
format = cmmTypeFormat ty
CmmStore addr src _alignment
| isFloatType ty -> assignMem_FltCode format addr src
| otherwise -> assignMem_IntCode format addr src
where ty = cmmExprType platform src
format = cmmTypeFormat ty
CmmBranch id -> genBranch id
CmmCondBranch arg true false _prediction ->
genCondBranch bid true false arg
CmmSwitch arg ids -> genSwitch arg ids
CmmCall { cml_target = arg } -> genJump arg
CmmUnwind _regs -> return nilOL
_ -> pprPanic "stmtToInstrs: statement should have been cps'd away" (pdoc platform stmt)
type InstrBlock
= OrdList Instr
data Register
= Fixed Format Reg InstrBlock
| Any Format (Reg -> InstrBlock)
swizzleRegisterRep :: Format -> Register -> Register
swizzleRegisterRep format (Fixed _ reg code) = Fixed format reg code
swizzleRegisterRep format (Any _ codefn) = Any format codefn
getRegisterReg :: Platform -> CmmReg -> Reg
getRegisterReg _ (CmmLocal (LocalReg u pk))
= RegVirtual $ mkVirtualReg u (cmmTypeFormat pk)
getRegisterReg platform (CmmGlobal mid)
= case globalRegMaybe platform mid of
Just reg -> RegReal reg
Nothing -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
getSomeReg :: CmmExpr -> NatM (Reg, Format, InstrBlock)
getSomeReg expr = do
r <- getRegister expr
case r of
Any rep code -> do
tmp <- getNewRegNat rep
return (tmp, rep, code tmp)
Fixed rep reg code ->
return (reg, rep, code)
getFloatReg :: HasCallStack => CmmExpr -> NatM (Reg, Format, InstrBlock)
getFloatReg expr = do
r <- getRegister expr
case r of
Any rep code | isFloatFormat rep -> do
tmp <- getNewRegNat rep
return (tmp, rep, code tmp)
Any II32 code -> do
tmp <- getNewRegNat FF32
return (tmp, FF32, code tmp)
Any II64 code -> do
tmp <- getNewRegNat FF64
return (tmp, FF64, code tmp)
Any _w _code -> do
config <- getConfig
pprPanic "can't do getFloatReg on" (pdoc (ncgPlatform config) expr)
Fixed rep reg code ->
return (reg, rep, code)
litToImm' :: CmmLit -> NatM (Operand, InstrBlock)
litToImm' lit = return (OpImm (litToImm lit), nilOL)
getRegister :: CmmExpr -> NatM Register
getRegister e = do
config <- getConfig
getRegister' config (ncgPlatform config) e
opRegWidth :: Width -> Width
opRegWidth W64 = W64
opRegWidth W32 = W32
opRegWidth W16 = W32
opRegWidth W8 = W32
opRegWidth w = pprPanic "opRegWidth" (text "Unsupported width" <+> ppr w)
getRegister' :: NCGConfig -> Platform -> CmmExpr -> NatM Register
getRegister' config plat (CmmMachOp (MO_Add w0) [x, CmmLit (CmmInt i w1)]) | i < 0
= getRegister' config plat (CmmMachOp (MO_Sub w0) [x, CmmLit (CmmInt (i) w1)])
getRegister' config plat (CmmMachOp (MO_Sub w0) [x, CmmLit (CmmInt i w1)]) | i < 0
= getRegister' config plat (CmmMachOp (MO_Add w0) [x, CmmLit (CmmInt (i) w1)])
getRegister' config plat expr
= case expr of
CmmReg (CmmGlobal PicBaseReg)
-> pprPanic "getRegisterReg-memory" (ppr $ PicBaseReg)
CmmLit lit
-> case lit of
CmmInt i W8 | i >= 0 -> do
return (Any (intFormat W8) (\dst -> unitOL $ annExpr expr (MOV (OpReg W8 dst) (OpImm (ImmInteger (narrowU W8 i))))))
CmmInt i W16 | i >= 0 -> do
return (Any (intFormat W16) (\dst -> unitOL $ annExpr expr (MOV (OpReg W16 dst) (OpImm (ImmInteger (narrowU W16 i))))))
CmmInt i W8 -> do
return (Any (intFormat W8) (\dst -> unitOL $ annExpr expr (MOV (OpReg W8 dst) (OpImm (ImmInteger (narrowU W8 i))))))
CmmInt i W16 -> do
return (Any (intFormat W16) (\dst -> unitOL $ annExpr expr (MOV (OpReg W16 dst) (OpImm (ImmInteger (narrowU W16 i))))))
CmmInt i w | isNbitEncodeable 16 i, i >= 0 -> do
return (Any (intFormat w) (\dst -> unitOL $ annExpr expr (MOV (OpReg W16 dst) (OpImm (ImmInteger i)))))
CmmInt i w | isNbitEncodeable 32 i, i >= 0 -> do
let half0 = fromIntegral (fromIntegral i :: Word16)
half1 = fromIntegral (fromIntegral (i `shiftR` 16) :: Word16)
return (Any (intFormat w) (\dst -> toOL [ annExpr expr
$ MOV (OpReg W32 dst) (OpImm (ImmInt half0))
, MOVK (OpReg W32 dst) (OpImmShift (ImmInt half1) SLSL 16)
]))
CmmInt i W32 -> do
let half0 = fromIntegral (fromIntegral i :: Word16)
half1 = fromIntegral (fromIntegral (i `shiftR` 16) :: Word16)
return (Any (intFormat W32) (\dst -> toOL [ annExpr expr
$ MOV (OpReg W32 dst) (OpImm (ImmInt half0))
, MOVK (OpReg W32 dst) (OpImmShift (ImmInt half1) SLSL 16)
]))
CmmInt i W64 -> do
let half0 = fromIntegral (fromIntegral i :: Word16)
half1 = fromIntegral (fromIntegral (i `shiftR` 16) :: Word16)
half2 = fromIntegral (fromIntegral (i `shiftR` 32) :: Word16)
half3 = fromIntegral (fromIntegral (i `shiftR` 48) :: Word16)
return (Any (intFormat W64) (\dst -> toOL [ annExpr expr
$ MOV (OpReg W64 dst) (OpImm (ImmInt half0))
, MOVK (OpReg W64 dst) (OpImmShift (ImmInt half1) SLSL 16)
, MOVK (OpReg W64 dst) (OpImmShift (ImmInt half2) SLSL 32)
, MOVK (OpReg W64 dst) (OpImmShift (ImmInt half3) SLSL 48)
]))
CmmInt _i rep -> do
(op, imm_code) <- litToImm' lit
return (Any (intFormat rep) (\dst -> imm_code `snocOL` annExpr expr (MOV (OpReg rep dst) op)))
CmmFloat 0 w -> do
(op, imm_code) <- litToImm' lit
return (Any (floatFormat w) (\dst -> imm_code `snocOL` annExpr expr (MOV (OpReg w dst) op)))
CmmFloat _f W8 -> pprPanic "getRegister' (CmmLit:CmmFloat), no support for bytes" (pdoc plat expr)
CmmFloat _f W16 -> pprPanic "getRegister' (CmmLit:CmmFloat), no support for halfs" (pdoc plat expr)
CmmFloat f W32 -> do
let word = castFloatToWord32 (fromRational f) :: Word32
half0 = fromIntegral (fromIntegral word :: Word16)
half1 = fromIntegral (fromIntegral (word `shiftR` 16) :: Word16)
tmp <- getNewRegNat (intFormat W32)
return (Any (floatFormat W32) (\dst -> toOL [ annExpr expr
$ MOV (OpReg W32 tmp) (OpImm (ImmInt half0))
, MOVK (OpReg W32 tmp) (OpImmShift (ImmInt half1) SLSL 16)
, MOV (OpReg W32 dst) (OpReg W32 tmp)
]))
CmmFloat f W64 -> do
let word = castDoubleToWord64 (fromRational f) :: Word64
half0 = fromIntegral (fromIntegral word :: Word16)
half1 = fromIntegral (fromIntegral (word `shiftR` 16) :: Word16)
half2 = fromIntegral (fromIntegral (word `shiftR` 32) :: Word16)
half3 = fromIntegral (fromIntegral (word `shiftR` 48) :: Word16)
tmp <- getNewRegNat (intFormat W64)
return (Any (floatFormat W64) (\dst -> toOL [ annExpr expr
$ MOV (OpReg W64 tmp) (OpImm (ImmInt half0))
, MOVK (OpReg W64 tmp) (OpImmShift (ImmInt half1) SLSL 16)
, MOVK (OpReg W64 tmp) (OpImmShift (ImmInt half2) SLSL 32)
, MOVK (OpReg W64 tmp) (OpImmShift (ImmInt half3) SLSL 48)
, MOV (OpReg W64 dst) (OpReg W64 tmp)
]))
CmmFloat _f _w -> pprPanic "getRegister' (CmmLit:CmmFloat), unsupported float lit" (pdoc plat expr)
CmmVec _ -> pprPanic "getRegister' (CmmLit:CmmVec): " (pdoc plat expr)
CmmLabel _lbl -> do
(op, imm_code) <- litToImm' lit
let rep = cmmLitType plat lit
format = cmmTypeFormat rep
return (Any format (\dst -> imm_code `snocOL` (annExpr expr $ LDR format (OpReg (formatToWidth format) dst) op)))
CmmLabelOff _lbl off | isNbitEncodeable 12 (fromIntegral off) -> do
(op, imm_code) <- litToImm' lit
let rep = cmmLitType plat lit
format = cmmTypeFormat rep
return (Any format (\dst -> imm_code `snocOL` LDR format (OpReg (formatToWidth format) dst) op))
CmmLabelOff lbl off -> do
(op, imm_code) <- litToImm' (CmmLabel lbl)
let rep = cmmLitType plat lit
format = cmmTypeFormat rep
width = typeWidth rep
(off_r, _off_format, off_code) <- getSomeReg $ CmmLit (CmmInt (fromIntegral off) width)
return (Any format (\dst -> imm_code `appOL` off_code `snocOL` LDR format (OpReg (formatToWidth format) dst) op `snocOL` ADD (OpReg width dst) (OpReg width dst) (OpReg width off_r)))
CmmLabelDiffOff _ _ _ _ -> pprPanic "getRegister' (CmmLit:CmmLabelOff): " (pdoc plat expr)
CmmBlock _ -> pprPanic "getRegister' (CmmLit:CmmLabelOff): " (pdoc plat expr)
CmmHighStackMark -> pprPanic "getRegister' (CmmLit:CmmLabelOff): " (pdoc plat expr)
CmmLoad mem rep _ -> do
Amode addr addr_code <- getAmode plat (typeWidth rep) mem
let format = cmmTypeFormat rep
return (Any format (\dst -> addr_code `snocOL` LDR format (OpReg (formatToWidth format) dst) (OpAddr addr)))
CmmStackSlot _ _
-> pprPanic "getRegister' (CmmStackSlot): " (pdoc plat expr)
CmmReg reg
-> return (Fixed (cmmTypeFormat (cmmRegType plat reg))
(getRegisterReg plat reg)
nilOL)
CmmRegOff reg off | isNbitEncodeable 12 (fromIntegral off) -> do
getRegister' config plat $
CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]
where width = typeWidth (cmmRegType plat reg)
CmmRegOff reg off -> do
(off_r, _off_format, off_code) <- getSomeReg $ CmmLit (CmmInt (fromIntegral off) width)
(reg, _format, code) <- getSomeReg $ CmmReg reg
return $ Any (intFormat width) (\dst -> off_code `appOL` code `snocOL` ADD (OpReg width dst) (OpReg width reg) (OpReg width off_r))
where width = typeWidth (cmmRegType plat reg)
CmmMachOp op [e] -> do
(reg, _format, code) <- getSomeReg e
case op of
MO_Not w -> return $ Any (intFormat w) $ \dst ->
let w' = opRegWidth w
in code `snocOL`
MVN (OpReg w' dst) (OpReg w' reg) `appOL`
truncateReg w' w dst
MO_S_Neg w -> negate code w reg
MO_F_Neg w -> return $ Any (floatFormat w) (\dst -> code `snocOL` NEG (OpReg w dst) (OpReg w reg))
MO_SF_Conv from to -> return $ Any (floatFormat to) (\dst -> code `snocOL` SCVTF (OpReg to dst) (OpReg from reg))
MO_FS_Conv from to -> return $ Any (intFormat to) (\dst -> code `snocOL` FCVTZS (OpReg to dst) (OpReg from reg))
MO_UU_Conv from to -> return $ Any (intFormat to) (\dst -> code `snocOL` UBFM (OpReg (max from to) dst) (OpReg (max from to) reg) (OpImm (ImmInt 0)) (toImm (min from to)))
MO_SS_Conv from to -> ss_conv from to reg code
MO_FF_Conv from to -> return $ Any (floatFormat to) (\dst -> code `snocOL` FCVT (OpReg to dst) (OpReg from reg))
MO_XX_Conv _from to -> swizzleRegisterRep (intFormat to) <$> getRegister e
_ -> pprPanic "getRegister' (monadic CmmMachOp):" (pdoc plat expr)
where
toImm W8 = (OpImm (ImmInt 7))
toImm W16 = (OpImm (ImmInt 15))
toImm W32 = (OpImm (ImmInt 31))
toImm W64 = (OpImm (ImmInt 63))
toImm W128 = (OpImm (ImmInt 127))
toImm W256 = (OpImm (ImmInt 255))
toImm W512 = (OpImm (ImmInt 511))
negate code w reg = do
let w' = opRegWidth w
(reg', code_sx) <- signExtendReg w w' reg
return $ Any (intFormat w) $ \dst ->
code `appOL`
code_sx `snocOL`
NEG (OpReg w' dst) (OpReg w' reg') `appOL`
truncateReg w' w dst
ss_conv from to reg code =
let w' = opRegWidth (max from to)
in return $ Any (intFormat to) $ \dst ->
code `snocOL`
SBFM (OpReg w' dst) (OpReg w' reg) (OpImm (ImmInt 0)) (toImm (min from to)) `appOL`
truncateReg w' to dst
CmmMachOp (MO_Add _) [expr'@(CmmReg (CmmGlobal _r)), CmmLit (CmmInt 0 _)] -> getRegister' config plat expr'
CmmMachOp (MO_Sub _) [expr'@(CmmReg (CmmGlobal _r)), CmmLit (CmmInt 0 _)] -> getRegister' config plat expr'
CmmMachOp (MO_Add w) [(CmmReg reg), CmmLit (CmmInt n _)]
| n > 0 && n < 4096 -> return $ Any (intFormat w) (\d -> unitOL $ annExpr expr (ADD (OpReg w d) (OpReg w' r') (OpImm (ImmInteger n))))
where w' = formatToWidth (cmmTypeFormat (cmmRegType plat reg))
r' = getRegisterReg plat reg
CmmMachOp (MO_Sub w) [(CmmReg reg), CmmLit (CmmInt n _)]
| n > 0 && n < 4096 -> return $ Any (intFormat w) (\d -> unitOL $ annExpr expr (SUB (OpReg w d) (OpReg w' r') (OpImm (ImmInteger n))))
where w' = formatToWidth (cmmTypeFormat (cmmRegType plat reg))
r' = getRegisterReg plat reg
CmmMachOp (MO_U_Quot w) [x, y] | w == W8 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (UXTB (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (UXTB (OpReg w reg_y) (OpReg w reg_y)) `snocOL` (UDIV (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_U_Quot w) [x, y] | w == W16 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (UXTH (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (UXTH (OpReg w reg_y) (OpReg w reg_y)) `snocOL` (UDIV (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_Shl w) [x, (CmmLit (CmmInt n _))] | w == W32, 0 <= n, n < 32 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (LSL (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_Shl w) [x, (CmmLit (CmmInt n _))] | w == W64, 0 <= n, n < 64 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (LSL (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_S_Shr w) [x, (CmmLit (CmmInt n _))] | w == W8, 0 <= n, n < 8 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (SBFX (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n)) (OpImm (ImmInteger (8n)))))
CmmMachOp (MO_S_Shr w) [x, y] | w == W8 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (SXTB (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (ASR (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_S_Shr w) [x, (CmmLit (CmmInt n _))] | w == W16, 0 <= n, n < 16 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (SBFX (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n)) (OpImm (ImmInteger (16n)))))
CmmMachOp (MO_S_Shr w) [x, y] | w == W16 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (SXTH (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (ASR (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_S_Shr w) [x, (CmmLit (CmmInt n _))] | w == W32, 0 <= n, n < 32 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (ASR (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_S_Shr w) [x, (CmmLit (CmmInt n _))] | w == W64, 0 <= n, n < 64 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (ASR (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_U_Shr w) [x, (CmmLit (CmmInt n _))] | w == W8, 0 <= n, n < 8 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (UBFX (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n)) (OpImm (ImmInteger (8n)))))
CmmMachOp (MO_U_Shr w) [x, y] | w == W8 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (UXTB (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (ASR (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_U_Shr w) [x, (CmmLit (CmmInt n _))] | w == W16, 0 <= n, n < 16 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (UBFX (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n)) (OpImm (ImmInteger (16n)))))
CmmMachOp (MO_U_Shr w) [x, y] | w == W16 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
return $ Any (intFormat w) (\dst -> code_x `appOL` code_y `snocOL` annExpr expr (UXTH (OpReg w reg_x) (OpReg w reg_x)) `snocOL` (ASR (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y)))
CmmMachOp (MO_U_Shr w) [x, (CmmLit (CmmInt n _))] | w == W32, 0 <= n, n < 32 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (LSR (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_U_Shr w) [x, (CmmLit (CmmInt n _))] | w == W64, 0 <= n, n < 64 -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ Any (intFormat w) (\dst -> code_x `snocOL` annExpr expr (LSR (OpReg w dst) (OpReg w reg_x) (OpImm (ImmInteger n))))
CmmMachOp (MO_And w) [(CmmReg reg), CmmLit (CmmInt n _)] | isAArch64Bitmask (fromIntegral n) ->
return $ Any (intFormat w) (\d -> unitOL $ annExpr expr (AND (OpReg w d) (OpReg w' r') (OpImm (ImmInteger n))))
where w' = formatToWidth (cmmTypeFormat (cmmRegType plat reg))
r' = getRegisterReg plat reg
CmmMachOp (MO_Or w) [(CmmReg reg), CmmLit (CmmInt n _)] | isAArch64Bitmask (fromIntegral n) ->
return $ Any (intFormat w) (\d -> unitOL $ annExpr expr (ORR (OpReg w d) (OpReg w' r') (OpImm (ImmInteger n))))
where w' = formatToWidth (cmmTypeFormat (cmmRegType plat reg))
r' = getRegisterReg plat reg
CmmMachOp op [x, y] -> do
let withTempIntReg w op = OpReg w <$> getNewRegNat (intFormat w) >>= op
bitOp w op = do
(reg_x, format_x, code_x) <- getSomeReg x
(reg_y, format_y, code_y) <- getSomeReg y
massertPpr (isIntFormat format_x == isIntFormat format_y) $ text "bitOp: incompatible"
return $ Any (intFormat w) (\dst ->
code_x `appOL`
code_y `appOL`
op (OpReg w dst) (OpReg w reg_x) (OpReg w reg_y))
intOp is_signed w op = do
(reg_x, format_x, code_x) <- getSomeReg x
(reg_y, format_y, code_y) <- getSomeReg y
massertPpr (isIntFormat format_x && isIntFormat format_y) $ text "intOp: non-int"
let w' = opRegWidth w
signExt r
| not is_signed = return (r, nilOL)
| otherwise = signExtendReg w w' r
(reg_x_sx, code_x_sx) <- signExt reg_x
(reg_y_sx, code_y_sx) <- signExt reg_y
return $ Any (intFormat w) $ \dst ->
code_x `appOL`
code_y `appOL`
code_x_sx `appOL`
code_y_sx `appOL`
op (OpReg w' dst) (OpReg w' reg_x_sx) (OpReg w' reg_y_sx) `appOL`
truncateReg w' w dst
floatOp w op = do
(reg_fx, format_x, code_fx) <- getFloatReg x
(reg_fy, format_y, code_fy) <- getFloatReg y
massertPpr (isFloatFormat format_x && isFloatFormat format_y) $ text "floatOp: non-float"
return $ Any (floatFormat w) (\dst -> code_fx `appOL` code_fy `appOL` op (OpReg w dst) (OpReg w reg_fx) (OpReg w reg_fy))
floatCond w op = do
(reg_fx, format_x, code_fx) <- getFloatReg x
(reg_fy, format_y, code_fy) <- getFloatReg y
massertPpr (isFloatFormat format_x && isFloatFormat format_y) $ text "floatCond: non-float"
return $ Any (intFormat w) (\dst -> code_fx `appOL` code_fy `appOL` op (OpReg w dst) (OpReg w reg_fx) (OpReg w reg_fy))
case op of
MO_Add w -> intOp False w (\d x y -> unitOL $ annExpr expr (ADD d x y))
MO_Sub w -> intOp False w (\d x y -> unitOL $ annExpr expr (SUB d x y))
MO_Eq w -> bitOp w (\d x y -> toOL [ CMP x y, CSET d EQ ])
MO_Ne w -> bitOp w (\d x y -> toOL [ CMP x y, CSET d NE ])
MO_Mul w -> intOp True w (\d x y -> unitOL $ MUL d x y)
MO_S_MulMayOflo w -> do_mul_may_oflo w x y
MO_S_Quot w -> intOp True w (\d x y -> unitOL $ SDIV d x y)
MO_S_Rem w -> withTempIntReg w $ \t ->
intOp True w (\d x y -> toOL [ SDIV t x y, MSUB d t y x ])
MO_U_MulMayOflo _w -> unsupportedP plat expr
MO_U_Quot w -> intOp False w (\d x y -> unitOL $ UDIV d x y)
MO_U_Rem w -> withTempIntReg w $ \t ->
intOp False w (\d x y -> toOL [ UDIV t x y, MSUB d t y x ])
MO_S_Ge w -> intOp True w (\d x y -> toOL [ CMP x y, CSET d SGE ])
MO_S_Le w -> intOp True w (\d x y -> toOL [ CMP x y, CSET d SLE ])
MO_S_Gt w -> intOp True w (\d x y -> toOL [ CMP x y, CSET d SGT ])
MO_S_Lt w -> intOp True w (\d x y -> toOL [ CMP x y, CSET d SLT ])
MO_U_Ge w -> intOp False w (\d x y -> toOL [ CMP x y, CSET d UGE ])
MO_U_Le w -> intOp False w (\d x y -> toOL [ CMP x y, CSET d ULE ])
MO_U_Gt w -> intOp False w (\d x y -> toOL [ CMP x y, CSET d UGT ])
MO_U_Lt w -> intOp False w (\d x y -> toOL [ CMP x y, CSET d ULT ])
MO_F_Add w -> floatOp w (\d x y -> unitOL $ ADD d x y)
MO_F_Sub w -> floatOp w (\d x y -> unitOL $ SUB d x y)
MO_F_Mul w -> floatOp w (\d x y -> unitOL $ MUL d x y)
MO_F_Quot w -> floatOp w (\d x y -> unitOL $ SDIV d x y)
MO_F_Eq w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d EQ ])
MO_F_Ne w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d NE ])
MO_F_Ge w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d OGE ])
MO_F_Le w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d OLE ])
MO_F_Gt w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d OGT ])
MO_F_Lt w -> floatCond w (\d x y -> toOL [ CMP x y, CSET d OLT ])
MO_And w -> bitOp w (\d x y -> unitOL $ AND d x y)
MO_Or w -> bitOp w (\d x y -> unitOL $ ORR d x y)
MO_Xor w -> bitOp w (\d x y -> unitOL $ EOR d x y)
MO_Shl w -> intOp False w (\d x y -> unitOL $ LSL d x y)
MO_U_Shr w -> intOp False w (\d x y -> unitOL $ LSR d x y)
MO_S_Shr w -> intOp True w (\d x y -> unitOL $ ASR d x y)
op -> pprPanic "getRegister' (unhandled dyadic CmmMachOp): " $ (pprMachOp op) <+> text "in" <+> (pdoc plat expr)
CmmMachOp _op _xs
-> pprPanic "getRegister' (variadic CmmMachOp): " (pdoc plat expr)
where
unsupportedP :: OutputableP env a => env -> a -> b
unsupportedP platform op = pprPanic "Unsupported op:" (pdoc platform op)
isNbitEncodeable :: Int -> Integer -> Bool
isNbitEncodeable n i = let shift = n 1 in (1 `shiftL` shift) <= i && i < (1 `shiftL` shift)
do_mul_may_oflo :: Width -> CmmExpr -> CmmExpr -> NatM Register
do_mul_may_oflo w@W64 x y = do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
lo <- getNewRegNat II64
hi <- getNewRegNat II64
return $ Any (intFormat w) (\dst ->
code_x `appOL`
code_y `snocOL`
MUL (OpReg w lo) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
SMULH (OpReg w hi) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
CMP (OpReg w hi) (OpRegShift w lo SASR 63) `snocOL`
CSET (OpReg w dst) NE)
do_mul_may_oflo w x y = do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
let tmp_w = case w of
W32 -> W64
W16 -> W32
W8 -> W32
_ -> panic "do_mul_may_oflo: impossible"
tmp <- getNewRegNat (intFormat tmp_w)
let ext_mode = case w of
W32 -> ESXTW
W16 -> ESXTH
W8 -> ESXTB
_ -> panic "do_mul_may_oflo: impossible"
mul = case w of
W32 -> SMULL
W16 -> MUL
W8 -> MUL
_ -> panic "do_mul_may_oflo: impossible"
return $ Any (intFormat w) (\dst ->
code_x `appOL`
code_y `snocOL`
mul (OpReg tmp_w tmp) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
CMP (OpReg tmp_w tmp) (OpRegExt tmp_w tmp ext_mode 0) `snocOL`
CSET (OpReg w dst) NE)
isAArch64Bitmask :: Integer -> Bool
isAArch64Bitmask 0 = False
isAArch64Bitmask n
| n == bit 64 1 = False
isAArch64Bitmask n =
check 64 || check 32 || check 16 || check 8
where
check width
| hasOneRun subpat =
let n' = fromIntegral (mkPat width subpat)
in n == n'
| otherwise = False
where
subpat :: Word64
subpat = fromIntegral (n .&. (bit width 1))
mkPat :: Int -> Word64 -> Word64
mkPat width subpat =
foldl' (.|.) 0 [ subpat `shiftL` p | p <- [0, width..63] ]
hasOneRun :: Word64 -> Bool
hasOneRun m =
64 == popCount m + countLeadingZeros m + countTrailingZeros m
signExtendReg :: Width -> Width -> Reg -> NatM (Reg, OrdList Instr)
signExtendReg w w' r =
case w of
W64 -> noop
W32
| w' == W32 -> noop
| otherwise -> extend SXTH
W16 -> extend SXTH
W8 -> extend SXTB
_ -> panic "intOp"
where
noop = return (r, nilOL)
extend instr = do
r' <- getNewRegNat II64
return (r', unitOL $ instr (OpReg w' r') (OpReg w' r))
truncateReg :: Width -> Width -> Reg -> OrdList Instr
truncateReg w w' r =
case w of
W64 -> nilOL
W32
| w' == W32 -> nilOL
_ -> unitOL $ UBFM (OpReg w r)
(OpReg w r)
(OpImm (ImmInt 0))
(OpImm $ ImmInt $ widthInBits w' 1)
data Amode = Amode AddrMode InstrBlock
getAmode :: Platform
-> Width
-> CmmExpr
-> NatM Amode
getAmode platform _ (CmmRegOff reg off) | 256 <= off, off <= 255
= return $ Amode (AddrRegImm reg' off') nilOL
where reg' = getRegisterReg platform reg
off' = ImmInt off
getAmode platform W32 (CmmRegOff reg off)
| 0 <= off, off <= 16380, off `mod` 4 == 0
= return $ Amode (AddrRegImm reg' off') nilOL
where reg' = getRegisterReg platform reg
off' = ImmInt off
getAmode platform W64 (CmmRegOff reg off)
| 0 <= off, off <= 32760, off `mod` 8 == 0
= return $ Amode (AddrRegImm reg' off') nilOL
where reg' = getRegisterReg platform reg
off' = ImmInt off
getAmode _platform _ (CmmMachOp (MO_Add _w) [expr, CmmLit (CmmInt off _w')])
| 256 <= off, off <= 255
= do (reg, _format, code) <- getSomeReg expr
return $ Amode (AddrRegImm reg (ImmInteger off)) code
getAmode _platform _ (CmmMachOp (MO_Sub _w) [expr, CmmLit (CmmInt off _w')])
| 256 <= off, off <= 255
= do (reg, _format, code) <- getSomeReg expr
return $ Amode (AddrRegImm reg (ImmInteger (off))) code
getAmode _platform _ expr
= do (reg, _format, code) <- getSomeReg expr
return $ Amode (AddrReg reg) code
assignMem_IntCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock
assignReg_IntCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock
assignMem_FltCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock
assignReg_FltCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock
assignMem_IntCode rep addrE srcE
= do
(src_reg, _format, code) <- getSomeReg srcE
platform <- getPlatform
let w = formatToWidth rep
Amode addr addr_code <- getAmode platform w addrE
return $ COMMENT (text "CmmStore" <+> parens (text (show addrE)) <+> parens (text (show srcE)))
`consOL` (code
`appOL` addr_code
`snocOL` STR rep (OpReg w src_reg) (OpAddr addr))
assignReg_IntCode _ reg src
= do
platform <- getPlatform
let dst = getRegisterReg platform reg
r <- getRegister src
return $ case r of
Any _ code -> COMMENT (text "CmmAssign" <+> parens (text (show reg)) <+> parens (text (show src))) `consOL` code dst
Fixed format freg fcode -> COMMENT (text "CmmAssign" <+> parens (text (show reg)) <+> parens (text (show src))) `consOL` (fcode `snocOL` MOV (OpReg (formatToWidth format) dst) (OpReg (formatToWidth format) freg))
assignMem_FltCode = assignMem_IntCode
assignReg_FltCode = assignReg_IntCode
genJump :: CmmExpr -> NatM InstrBlock
genJump expr@(CmmLit (CmmLabel lbl))
= return $ unitOL (annExpr expr (J (TLabel lbl)))
genJump expr = do
(target, _format, code) <- getSomeReg expr
return (code `appOL` unitOL (annExpr expr (J (TReg target))))
genBranch :: BlockId -> NatM InstrBlock
genBranch = return . toOL . mkJumpInstr
genCondJump
:: BlockId
-> CmmExpr
-> NatM InstrBlock
genCondJump bid expr = do
case expr of
CmmMachOp (MO_Eq w) [x, CmmLit (CmmInt 0 _)] -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ code_x `snocOL` (annExpr expr (CBZ (OpReg w reg_x) (TBlock bid)))
CmmMachOp (MO_Ne w) [x, CmmLit (CmmInt 0 _)] -> do
(reg_x, _format_x, code_x) <- getSomeReg x
return $ code_x `snocOL` (annExpr expr (CBNZ (OpReg w reg_x) (TBlock bid)))
CmmMachOp mop [x, y] -> do
let ubcond w cmp = do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
let x' = OpReg w reg_x
y' = OpReg w reg_y
return $ case w of
W8 -> code_x `appOL` code_y `appOL` toOL [ UXTB x' x', UXTB y' y', CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
W16 -> code_x `appOL` code_y `appOL` toOL [ UXTH x' x', UXTH y' y', CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
_ -> code_x `appOL` code_y `appOL` toOL [ CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
sbcond w cmp = do
(reg_x, _format_x, code_x) <- getSomeReg x
(reg_y, _format_y, code_y) <- getSomeReg y
let x' = OpReg w reg_x
y' = OpReg w reg_y
return $ case w of
W8 -> code_x `appOL` code_y `appOL` toOL [ SXTB x' x', SXTB y' y', CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
W16 -> code_x `appOL` code_y `appOL` toOL [ SXTH x' x', SXTH y' y', CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
_ -> code_x `appOL` code_y `appOL` toOL [ CMP x' y', (annExpr expr (BCOND cmp (TBlock bid))) ]
fbcond w cmp = do
(reg_fx, _format_fx, code_fx) <- getFloatReg x
(reg_fy, _format_fy, code_fy) <- getFloatReg y
return $ code_fx `appOL` code_fy `snocOL` CMP (OpReg w reg_fx) (OpReg w reg_fy) `snocOL` (annExpr expr (BCOND cmp (TBlock bid)))
case mop of
MO_F_Eq w -> fbcond w EQ
MO_F_Ne w -> fbcond w NE
MO_F_Gt w -> fbcond w OGT
MO_F_Ge w -> fbcond w OGE
MO_F_Lt w -> fbcond w OLT
MO_F_Le w -> fbcond w OLE
MO_Eq w -> sbcond w EQ
MO_Ne w -> sbcond w NE
MO_S_Gt w -> sbcond w SGT
MO_S_Ge w -> sbcond w SGE
MO_S_Lt w -> sbcond w SLT
MO_S_Le w -> sbcond w SLE
MO_U_Gt w -> ubcond w UGT
MO_U_Ge w -> ubcond w UGE
MO_U_Lt w -> ubcond w ULT
MO_U_Le w -> ubcond w ULE
_ -> pprPanic "AArch64.genCondJump:case mop: " (text $ show expr)
_ -> pprPanic "AArch64.genCondJump: " (text $ show expr)
genCondBranch
:: BlockId
-> BlockId
-> BlockId
-> CmmExpr
-> NatM InstrBlock
genCondBranch _ true false expr = do
b1 <- genCondJump true expr
b2 <- genBranch false
return (b1 `appOL` b2)
genCCall
:: ForeignTarget
-> [CmmFormal]
-> [CmmActual]
-> BlockId
-> NatM (InstrBlock, Maybe BlockId)
genCCall target dest_regs arg_regs bid = do
case target of
ForeignTarget expr _cconv -> do
(call_target, call_target_code) <- case expr of
(CmmLit (CmmLabel lbl)) -> pure (TLabel lbl, nilOL)
_ -> do (reg, _format, reg_code) <- getSomeReg expr
pure (TReg reg, reg_code)
arg_regs' <- mapM getSomeReg arg_regs
let (_res_hints, arg_hints) = foreignTargetHints target
arg_regs'' = zipWith (\(r, f, c) h -> (r,f,h,c)) arg_regs' arg_hints
platform <- getPlatform
let packStack = platformOS platform == OSDarwin
(stackSpace', passRegs, passArgumentsCode) <- passArguments packStack allGpArgRegs allFpArgRegs arg_regs'' 0 [] nilOL
let stackSpace = if stackSpace' `mod` 8 /= 0
then 8 * (stackSpace' `div` 8 + 1)
else stackSpace'
(returnRegs, readResultsCode) <- readResults allGpArgRegs allFpArgRegs dest_regs [] nilOL
let moveStackDown 0 = toOL [ PUSH_STACK_FRAME
, DELTA (16) ]
moveStackDown i | odd i = moveStackDown (i + 1)
moveStackDown i = toOL [ PUSH_STACK_FRAME
, SUB (OpReg W64 (regSingle 31)) (OpReg W64 (regSingle 31)) (OpImm (ImmInt (8 * i)))
, DELTA (8 * i 16) ]
moveStackUp 0 = toOL [ POP_STACK_FRAME
, DELTA 0 ]
moveStackUp i | odd i = moveStackUp (i + 1)
moveStackUp i = toOL [ ADD (OpReg W64 (regSingle 31)) (OpReg W64 (regSingle 31)) (OpImm (ImmInt (8 * i)))
, POP_STACK_FRAME
, DELTA 0 ]
let code = call_target_code
`appOL` moveStackDown (stackSpace `div` 8)
`appOL` passArgumentsCode
`appOL` (unitOL $ BL call_target passRegs returnRegs)
`appOL` readResultsCode
`appOL` moveStackUp (stackSpace `div` 8)
return (code, Nothing)
PrimTarget MO_F32_Fabs
| [arg_reg] <- arg_regs, [dest_reg] <- dest_regs ->
unaryFloatOp W32 (\d x -> unitOL $ FABS d x) arg_reg dest_reg
PrimTarget MO_F64_Fabs
| [arg_reg] <- arg_regs, [dest_reg] <- dest_regs ->
unaryFloatOp W64 (\d x -> unitOL $ FABS d x) arg_reg dest_reg
PrimTarget mop -> do
case mop of
MO_F64_Pwr -> mkCCall "pow"
MO_F64_Sin -> mkCCall "sin"
MO_F64_Cos -> mkCCall "cos"
MO_F64_Tan -> mkCCall "tan"
MO_F64_Sinh -> mkCCall "sinh"
MO_F64_Cosh -> mkCCall "cosh"
MO_F64_Tanh -> mkCCall "tanh"
MO_F64_Asin -> mkCCall "asin"
MO_F64_Acos -> mkCCall "acos"
MO_F64_Atan -> mkCCall "atan"
MO_F64_Asinh -> mkCCall "asinh"
MO_F64_Acosh -> mkCCall "acosh"
MO_F64_Atanh -> mkCCall "atanh"
MO_F64_Log -> mkCCall "log"
MO_F64_Log1P -> mkCCall "log1p"
MO_F64_Exp -> mkCCall "exp"
MO_F64_ExpM1 -> mkCCall "expm1"
MO_F64_Fabs -> mkCCall "fabs"
MO_F64_Sqrt -> mkCCall "sqrt"
MO_F32_Pwr -> mkCCall "powf"
MO_F32_Sin -> mkCCall "sinf"
MO_F32_Cos -> mkCCall "cosf"
MO_F32_Tan -> mkCCall "tanf"
MO_F32_Sinh -> mkCCall "sinhf"
MO_F32_Cosh -> mkCCall "coshf"
MO_F32_Tanh -> mkCCall "tanhf"
MO_F32_Asin -> mkCCall "asinf"
MO_F32_Acos -> mkCCall "acosf"
MO_F32_Atan -> mkCCall "atanf"
MO_F32_Asinh -> mkCCall "asinhf"
MO_F32_Acosh -> mkCCall "acoshf"
MO_F32_Atanh -> mkCCall "atanhf"
MO_F32_Log -> mkCCall "logf"
MO_F32_Log1P -> mkCCall "log1pf"
MO_F32_Exp -> mkCCall "expf"
MO_F32_ExpM1 -> mkCCall "expm1f"
MO_F32_Fabs -> mkCCall "fabsf"
MO_F32_Sqrt -> mkCCall "sqrtf"
MO_I64_ToI -> mkCCall "hs_int64ToInt"
MO_I64_FromI -> mkCCall "hs_intToInt64"
MO_W64_ToW -> mkCCall "hs_word64ToWord"
MO_W64_FromW -> mkCCall "hs_wordToWord64"
MO_x64_Neg -> mkCCall "hs_neg64"
MO_x64_Add -> mkCCall "hs_add64"
MO_x64_Sub -> mkCCall "hs_sub64"
MO_x64_Mul -> mkCCall "hs_mul64"
MO_I64_Quot -> mkCCall "hs_quotInt64"
MO_I64_Rem -> mkCCall "hs_remInt64"
MO_W64_Quot -> mkCCall "hs_quotWord64"
MO_W64_Rem -> mkCCall "hs_remWord64"
MO_x64_And -> mkCCall "hs_and64"
MO_x64_Or -> mkCCall "hs_or64"
MO_x64_Xor -> mkCCall "hs_xor64"
MO_x64_Not -> mkCCall "hs_not64"
MO_x64_Shl -> mkCCall "hs_uncheckedShiftL64"
MO_I64_Shr -> mkCCall "hs_uncheckedIShiftRA64"
MO_W64_Shr -> mkCCall "hs_uncheckedShiftRL64"
MO_x64_Eq -> mkCCall "hs_eq64"
MO_x64_Ne -> mkCCall "hs_ne64"
MO_I64_Ge -> mkCCall "hs_geInt64"
MO_I64_Gt -> mkCCall "hs_gtInt64"
MO_I64_Le -> mkCCall "hs_leInt64"
MO_I64_Lt -> mkCCall "hs_ltInt64"
MO_W64_Ge -> mkCCall "hs_geWord64"
MO_W64_Gt -> mkCCall "hs_gtWord64"
MO_W64_Le -> mkCCall "hs_leWord64"
MO_W64_Lt -> mkCCall "hs_ltWord64"
MO_UF_Conv w -> mkCCall (word2FloatLabel w)
MO_S_Mul2 _w -> unsupported mop
MO_S_QuotRem _w -> unsupported mop
MO_U_QuotRem _w -> unsupported mop
MO_U_QuotRem2 _w -> unsupported mop
MO_Add2 _w -> unsupported mop
MO_AddWordC _w -> unsupported mop
MO_SubWordC _w -> unsupported mop
MO_AddIntC _w -> unsupported mop
MO_SubIntC _w -> unsupported mop
MO_U_Mul2 _w -> unsupported mop
MO_ReadBarrier -> return (unitOL DMBSY, Nothing)
MO_WriteBarrier -> return (unitOL DMBSY, Nothing)
MO_Touch -> return (nilOL, Nothing)
MO_Prefetch_Data _n -> return (nilOL, Nothing)
MO_Memcpy _align -> mkCCall "memcpy"
MO_Memset _align -> mkCCall "memset"
MO_Memmove _align -> mkCCall "memmove"
MO_Memcmp _align -> mkCCall "memcmp"
MO_SuspendThread -> mkCCall "suspendThread"
MO_ResumeThread -> mkCCall "resumeThread"
MO_PopCnt w -> mkCCall (popCntLabel w)
MO_Pdep w -> mkCCall (pdepLabel w)
MO_Pext w -> mkCCall (pextLabel w)
MO_Clz w -> mkCCall (clzLabel w)
MO_Ctz w -> mkCCall (ctzLabel w)
MO_BSwap w -> mkCCall (bSwapLabel w)
MO_BRev w -> mkCCall (bRevLabel w)
MO_AtomicRMW w amop -> mkCCall (atomicRMWLabel w amop)
MO_AtomicRead w _ -> mkCCall (atomicReadLabel w)
MO_AtomicWrite w _ -> mkCCall (atomicWriteLabel w)
MO_Cmpxchg w -> mkCCall (cmpxchgLabel w)
MO_Xchg w -> mkCCall (xchgLabel w)
where
unsupported :: Show a => a -> b
unsupported mop = panic ("outOfLineCmmOp: " ++ show mop
++ " not supported here")
mkCCall :: FastString -> NatM (InstrBlock, Maybe BlockId)
mkCCall name = do
config <- getConfig
target <- cmmMakeDynamicReference config CallReference $
mkForeignLabel name Nothing ForeignLabelInThisPackage IsFunction
let cconv = ForeignConvention CCallConv [NoHint] [NoHint] CmmMayReturn
genCCall (ForeignTarget target cconv) dest_regs arg_regs bid
passArguments :: Bool -> [Reg] -> [Reg] -> [(Reg, Format, ForeignHint, InstrBlock)] -> Int -> [Reg] -> InstrBlock -> NatM (Int, [Reg], InstrBlock)
passArguments _packStack _ _ [] stackSpace accumRegs accumCode = return (stackSpace, accumRegs, accumCode)
passArguments pack (gpReg:gpRegs) fpRegs ((r, format, hint, code_r):args) stackSpace accumRegs accumCode | isIntFormat format = do
platform <- getPlatform
let w = formatToWidth format
mov
| w < W32
, platformCConvNeedsExtension platform
, SignedHint <- hint
= case w of
W8 -> SXTB (OpReg W64 gpReg) (OpReg w r)
W16 -> SXTH (OpReg W64 gpReg) (OpReg w r)
_ -> panic "impossible"
| otherwise
= MOV (OpReg w gpReg) (OpReg w r)
accumCode' = accumCode `appOL`
code_r `snocOL`
ann (text "Pass gp argument: " <> ppr r) mov
passArguments pack gpRegs fpRegs args stackSpace (gpReg:accumRegs) accumCode'
passArguments pack gpRegs (fpReg:fpRegs) ((r, format, _hint, code_r):args) stackSpace accumRegs accumCode | isFloatFormat format = do
let w = formatToWidth format
mov = MOV (OpReg w fpReg) (OpReg w r)
accumCode' = accumCode `appOL`
code_r `snocOL`
ann (text "Pass fp argument: " <> ppr r) mov
passArguments pack gpRegs fpRegs args stackSpace (fpReg:accumRegs) accumCode'
passArguments pack [] [] ((r, format, _hint, code_r):args) stackSpace accumRegs accumCode = do
let w = formatToWidth format
bytes = widthInBits w `div` 8
space = if pack then bytes else 8
stackSpace' | pack && stackSpace `mod` space /= 0 = stackSpace + space (stackSpace `mod` space)
| otherwise = stackSpace
str = STR format (OpReg w r) (OpAddr (AddrRegImm (regSingle 31) (ImmInt stackSpace')))
stackCode = code_r `snocOL`
ann (text "Pass argument (size " <> ppr w <> text ") on the stack: " <> ppr r) str
passArguments pack [] [] args (stackSpace'+space) accumRegs (stackCode `appOL` accumCode)
passArguments pack [] fpRegs ((r, format, _hint, code_r):args) stackSpace accumRegs accumCode | isIntFormat format = do
let w = formatToWidth format
bytes = widthInBits w `div` 8
space = if pack then bytes else 8
stackSpace' | pack && stackSpace `mod` space /= 0 = stackSpace + space (stackSpace `mod` space)
| otherwise = stackSpace
str = STR format (OpReg w r) (OpAddr (AddrRegImm (regSingle 31) (ImmInt stackSpace')))
stackCode = code_r `snocOL`
ann (text "Pass argument (size " <> ppr w <> text ") on the stack: " <> ppr r) str
passArguments pack [] fpRegs args (stackSpace'+space) accumRegs (stackCode `appOL` accumCode)
passArguments pack gpRegs [] ((r, format, _hint, code_r):args) stackSpace accumRegs accumCode | isFloatFormat format = do
let w = formatToWidth format
bytes = widthInBits w `div` 8
space = if pack then bytes else 8
stackSpace' | pack && stackSpace `mod` space /= 0 = stackSpace + space (stackSpace `mod` space)
| otherwise = stackSpace
str = STR format (OpReg w r) (OpAddr (AddrRegImm (regSingle 31) (ImmInt stackSpace')))
stackCode = code_r `snocOL`
ann (text "Pass argument (size " <> ppr w <> text ") on the stack: " <> ppr r) str
passArguments pack gpRegs [] args (stackSpace'+space) accumRegs (stackCode `appOL` accumCode)
passArguments _ _ _ _ _ _ _ = pprPanic "passArguments" (text "invalid state")
readResults :: [Reg] -> [Reg] -> [LocalReg] -> [Reg]-> InstrBlock -> NatM ([Reg], InstrBlock)
readResults _ _ [] accumRegs accumCode = return (accumRegs, accumCode)
readResults [] _ _ _ _ = do
platform <- getPlatform
pprPanic "genCCall, out of gp registers when reading results" (pdoc platform target)
readResults _ [] _ _ _ = do
platform <- getPlatform
pprPanic "genCCall, out of fp registers when reading results" (pdoc platform target)
readResults (gpReg:gpRegs) (fpReg:fpRegs) (dst:dsts) accumRegs accumCode = do
platform <- getPlatform
let rep = cmmRegType platform (CmmLocal dst)
format = cmmTypeFormat rep
w = cmmRegWidth platform (CmmLocal dst)
r_dst = getRegisterReg platform (CmmLocal dst)
if isFloatFormat format
then readResults (gpReg:gpRegs) fpRegs dsts (fpReg:accumRegs) (accumCode `snocOL` MOV (OpReg w r_dst) (OpReg w fpReg))
else readResults gpRegs (fpReg:fpRegs) dsts (gpReg:accumRegs) (accumCode `snocOL` MOV (OpReg w r_dst) (OpReg w gpReg))
unaryFloatOp w op arg_reg dest_reg = do
platform <- getPlatform
(reg_fx, _format_x, code_fx) <- getFloatReg arg_reg
let dst = getRegisterReg platform (CmmLocal dest_reg)
let code = code_fx `appOL` op (OpReg w dst) (OpReg w reg_fx)
return (code, Nothing)