module StgCmmLayout (
mkArgDescr,
emitCall, emitReturn, adjustHpBackwards,
emitClosureProcAndInfoTable,
emitClosureAndInfoTable,
slowCall, directCall,
mkVirtHeapOffsets, mkVirtConstrOffsets, getHpRelOffset, hpRel,
stdInfoTableSizeB,
entryCode, closureInfoPtr,
getConstrTag,
cmmGetClosureType,
infoTable, infoTableClosureType,
infoTablePtrs, infoTableNonPtrs,
funInfoTable
) where
#include "HsVersions.h"
import StgCmmClosure
import StgCmmEnv
import StgCmmTicky
import StgCmmMonad
import StgCmmUtils
import StgCmmProf
import MkGraph
import SMRep
import Cmm
import CmmUtils
import CLabel
import StgSyn
import Id
import Name
import TyCon ( PrimRep(..) )
import BasicTypes ( RepArity )
import StaticFlags
import Module
import Constants
import Util
import Data.List
import Outputable
import FastString
emitReturn :: [CmmExpr] -> FCode ()
emitReturn results
= do { sequel <- getSequel;
; updfr_off <- getUpdFrameOff
; emitComment $ mkFastString ("emitReturn: " ++ show sequel)
; case sequel of
Return _ ->
do { adjustHpBackwards
; emit (mkReturnSimple results updfr_off) }
AssignTo regs adjust ->
do { if adjust then adjustHpBackwards else return ()
; emitMultiAssign regs results }
}
emitCall :: (Convention, Convention) -> CmmExpr -> [CmmExpr] -> FCode ()
emitCall convs fun args
= emitCallWithExtraStack convs fun args noExtraStack
emitCallWithExtraStack
:: (Convention, Convention) -> CmmExpr -> [CmmExpr]
-> (ByteOff, [(CmmExpr,ByteOff)]) -> FCode ()
emitCallWithExtraStack convs@(callConv, _) fun args extra_stack
= do { adjustHpBackwards
; sequel <- getSequel
; updfr_off <- getUpdFrameOff
; emitComment $ mkFastString ("emitCallWithExtraStack: " ++ show sequel)
; case sequel of
Return _ ->
emit $ mkForeignJumpExtra callConv fun args updfr_off extra_stack
AssignTo res_regs _ -> do
emit =<< mkCall fun convs res_regs args updfr_off extra_stack
}
adjustHpBackwards :: FCode ()
adjustHpBackwards
= do { hp_usg <- getHpUsage
; let rHp = realHp hp_usg
vHp = virtHp hp_usg
adjust_words = vHp rHp
; new_hp <- getHpRelOffset vHp
; emit (if adjust_words == 0
then mkNop
else mkAssign hpReg new_hp)
; tickyAllocHeap adjust_words
; setRealHp vHp
}
directCall :: Convention -> CLabel -> RepArity -> [StgArg] -> FCode ()
directCall conv lbl arity stg_args
= do { argreps <- getArgRepsAmodes stg_args
; direct_call "directCall" conv lbl arity argreps }
slowCall :: CmmExpr -> [StgArg] -> FCode ()
slowCall fun stg_args
= do { dflags <- getDynFlags
; argsreps <- getArgRepsAmodes stg_args
; let (rts_fun, arity) = slowCallPattern (map fst argsreps)
; direct_call "slow_call" NativeNodeCall
(mkRtsApFastLabel rts_fun) arity ((P,Just fun):argsreps)
; emitComment $ mkFastString ("slow_call for " ++
showSDoc dflags (ppr fun) ++
" with pat " ++ unpackFS rts_fun)
}
direct_call :: String
-> Convention
-> CLabel -> RepArity
-> [(ArgRep,Maybe CmmExpr)] -> FCode ()
direct_call caller call_conv lbl arity args
| debugIsOn && real_arity > length args
= do
pprPanic "direct_call" $
text caller <+> ppr arity <+>
ppr lbl <+> ppr (length args) <+>
ppr (map snd args) <+> ppr (map fst args)
| null rest_args
= emitCall (call_conv, NativeReturn) target (nonVArgs args)
| otherwise
= emitCallWithExtraStack (call_conv, NativeReturn)
target (nonVArgs fast_args) (mkStkOffsets stack_args)
where
target = CmmLit (CmmLabel lbl)
(fast_args, rest_args) = splitAt real_arity args
stack_args = slowArgs rest_args
real_arity = case call_conv of
NativeNodeCall -> arity+1
_ -> arity
getArgRepsAmodes :: [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
getArgRepsAmodes = mapM getArgRepAmode
where getArgRepAmode arg
| V <- rep = return (V, Nothing)
| otherwise = do expr <- getArgAmode (NonVoid arg)
return (rep, Just expr)
where rep = toArgRep (argPrimRep arg)
nonVArgs :: [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [] = []
nonVArgs ((_,Nothing) : args) = nonVArgs args
nonVArgs ((_,Just arg) : args) = arg : nonVArgs args
slowArgs :: [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs [] = []
slowArgs args
| opt_SccProfilingOn = save_cccs ++ this_pat ++ slowArgs rest_args
| otherwise = this_pat ++ slowArgs rest_args
where
(arg_pat, n) = slowCallPattern (map fst args)
(call_args, rest_args) = splitAt n args
stg_ap_pat = mkCmmRetInfoLabel rtsPackageId arg_pat
this_pat = (N, Just (mkLblExpr stg_ap_pat)) : call_args
save_cccs = [(N, Just (mkLblExpr save_cccs_lbl)), (N, Just curCCS)]
save_cccs_lbl = mkCmmRetInfoLabel rtsPackageId (fsLit "stg_restore_cccs")
slowCallPattern :: [ArgRep] -> (FastString, RepArity)
slowCallPattern (P: P: P: P: P: P: _) = (fsLit "stg_ap_pppppp", 6)
slowCallPattern (P: P: P: P: P: _) = (fsLit "stg_ap_ppppp", 5)
slowCallPattern (P: P: P: P: _) = (fsLit "stg_ap_pppp", 4)
slowCallPattern (P: P: P: V: _) = (fsLit "stg_ap_pppv", 4)
slowCallPattern (P: P: P: _) = (fsLit "stg_ap_ppp", 3)
slowCallPattern (P: P: V: _) = (fsLit "stg_ap_ppv", 3)
slowCallPattern (P: P: _) = (fsLit "stg_ap_pp", 2)
slowCallPattern (P: V: _) = (fsLit "stg_ap_pv", 2)
slowCallPattern (P: _) = (fsLit "stg_ap_p", 1)
slowCallPattern (V: _) = (fsLit "stg_ap_v", 1)
slowCallPattern (N: _) = (fsLit "stg_ap_n", 1)
slowCallPattern (F: _) = (fsLit "stg_ap_f", 1)
slowCallPattern (D: _) = (fsLit "stg_ap_d", 1)
slowCallPattern (L: _) = (fsLit "stg_ap_l", 1)
slowCallPattern [] = (fsLit "stg_ap_0", 0)
mkStkOffsets
:: [(ArgRep, Maybe CmmExpr)]
-> ( ByteOff
, [(CmmExpr, ByteOff)] )
mkStkOffsets things
= loop 0 [] (reverse things)
where
loop offset offs [] = (offset,offs)
loop offset offs ((_,Nothing):things) = loop offset offs things
loop offset offs ((rep,Just thing):things)
= loop thing_off ((thing, thing_off):offs) things
where
thing_off = offset + argRepSizeW rep * wORD_SIZE
data ArgRep = P
| N
| L
| V
| F
| D
instance Outputable ArgRep where
ppr P = text "P"
ppr N = text "N"
ppr L = text "L"
ppr V = text "V"
ppr F = text "F"
ppr D = text "D"
toArgRep :: PrimRep -> ArgRep
toArgRep VoidRep = V
toArgRep PtrRep = P
toArgRep IntRep = N
toArgRep WordRep = N
toArgRep AddrRep = N
toArgRep Int64Rep = L
toArgRep Word64Rep = L
toArgRep FloatRep = F
toArgRep DoubleRep = D
isNonV :: ArgRep -> Bool
isNonV V = False
isNonV _ = True
argRepSizeW :: ArgRep -> WordOff
argRepSizeW N = 1
argRepSizeW P = 1
argRepSizeW F = 1
argRepSizeW L = wORD64_SIZE `quot` wORD_SIZE
argRepSizeW D = dOUBLE_SIZE `quot` wORD_SIZE
argRepSizeW V = 0
idArgRep :: Id -> ArgRep
idArgRep = toArgRep . idPrimRep
hpRel :: VirtualHpOffset
-> VirtualHpOffset
-> WordOff
hpRel hp off = off hp
getHpRelOffset :: VirtualHpOffset -> FCode CmmExpr
getHpRelOffset virtual_offset
= do { hp_usg <- getHpUsage
; return (cmmRegOffW hpReg (hpRel (realHp hp_usg) virtual_offset)) }
mkVirtHeapOffsets
:: Bool
-> [(PrimRep,a)]
-> (WordOff,
WordOff,
[(NonVoid a, VirtualHpOffset)])
mkVirtHeapOffsets is_thunk things
= let non_void_things = filterOut (isVoidRep . fst) things
(ptrs, non_ptrs) = partition (isGcPtrRep . fst) non_void_things
(wds_of_ptrs, ptrs_w_offsets) = mapAccumL computeOffset 0 ptrs
(tot_wds, non_ptrs_w_offsets) = mapAccumL computeOffset wds_of_ptrs non_ptrs
in
(tot_wds, wds_of_ptrs, ptrs_w_offsets ++ non_ptrs_w_offsets)
where
hdr_size | is_thunk = thunkHdrSize
| otherwise = fixedHdrSize
computeOffset wds_so_far (rep, thing)
= (wds_so_far + argRepSizeW (toArgRep rep),
(NonVoid thing, hdr_size + wds_so_far))
mkVirtConstrOffsets :: [(PrimRep,a)] -> (WordOff, WordOff, [(NonVoid a, VirtualHpOffset)])
mkVirtConstrOffsets = mkVirtHeapOffsets False
#include "../includes/rts/storage/FunTypes.h"
mkArgDescr :: Name -> [Id] -> FCode ArgDescr
mkArgDescr _nm args
= case stdPattern arg_reps of
Just spec_id -> return (ArgSpec spec_id)
Nothing -> return (ArgGen arg_bits)
where
arg_bits = argBits arg_reps
arg_reps = filter isNonV (map idArgRep args)
argBits :: [ArgRep] -> [Bool]
argBits [] = []
argBits (P : args) = False : argBits args
argBits (arg : args) = take (argRepSizeW arg) (repeat True) ++ argBits args
stdPattern :: [ArgRep] -> Maybe StgHalfWord
stdPattern reps
= case reps of
[] -> Just ARG_NONE
[N] -> Just ARG_N
[P] -> Just ARG_P
[F] -> Just ARG_F
[D] -> Just ARG_D
[L] -> Just ARG_L
[N,N] -> Just ARG_NN
[N,P] -> Just ARG_NP
[P,N] -> Just ARG_PN
[P,P] -> Just ARG_PP
[N,N,N] -> Just ARG_NNN
[N,N,P] -> Just ARG_NNP
[N,P,N] -> Just ARG_NPN
[N,P,P] -> Just ARG_NPP
[P,N,N] -> Just ARG_PNN
[P,N,P] -> Just ARG_PNP
[P,P,N] -> Just ARG_PPN
[P,P,P] -> Just ARG_PPP
[P,P,P,P] -> Just ARG_PPPP
[P,P,P,P,P] -> Just ARG_PPPPP
[P,P,P,P,P,P] -> Just ARG_PPPPPP
_ -> Nothing
emitClosureProcAndInfoTable :: Bool
-> Id
-> LambdaFormInfo
-> CmmInfoTable
-> [NonVoid Id]
-> ((Int, LocalReg, [LocalReg]) -> FCode ())
-> FCode ()
emitClosureProcAndInfoTable top_lvl bndr lf_info info_tbl args body
= do {
; node <- if top_lvl then return $ idToReg (NonVoid bndr)
else bindToReg (NonVoid bndr) lf_info
; let node_points = nodeMustPointToIt lf_info
; arg_regs <- bindArgsToRegs args
; let args' = if node_points then (node : arg_regs) else arg_regs
conv = if nodeMustPointToIt lf_info then NativeNodeCall
else NativeDirectCall
(offset, _) = mkCallEntry conv args'
; emitClosureAndInfoTable info_tbl conv args' $ body (offset, node, arg_regs)
}
emitClosureAndInfoTable ::
CmmInfoTable -> Convention -> [LocalReg] -> FCode () -> FCode ()
emitClosureAndInfoTable info_tbl conv args body
= do { blks <- getCode body
; let entry_lbl = toEntryLbl (cit_lbl info_tbl)
; emitProcWithConvention conv info_tbl entry_lbl args blks
}
stdInfoTableSizeW :: WordOff
stdInfoTableSizeW
= size_fixed + size_prof
where
size_fixed = 2
size_prof | opt_SccProfilingOn = 2
| otherwise = 0
stdInfoTableSizeB :: ByteOff
stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE :: ByteOff
stdSrtBitmapOffset :: ByteOff
stdSrtBitmapOffset = stdInfoTableSizeB hALF_WORD_SIZE
stdClosureTypeOffset :: ByteOff
stdClosureTypeOffset = stdInfoTableSizeB wORD_SIZE
stdPtrsOffset, stdNonPtrsOffset :: ByteOff
stdPtrsOffset = stdInfoTableSizeB 2*wORD_SIZE
stdNonPtrsOffset = stdInfoTableSizeB 2*wORD_SIZE + hALF_WORD_SIZE
closureInfoPtr :: CmmExpr -> CmmExpr
closureInfoPtr e = CmmLoad e bWord
entryCode :: CmmExpr -> CmmExpr
entryCode e | tablesNextToCode = e
| otherwise = CmmLoad e bWord
getConstrTag :: CmmExpr -> CmmExpr
getConstrTag closure_ptr
= CmmMachOp (MO_UU_Conv halfWordWidth wordWidth) [infoTableConstrTag info_table]
where
info_table = infoTable (closureInfoPtr closure_ptr)
cmmGetClosureType :: CmmExpr -> CmmExpr
cmmGetClosureType closure_ptr
= CmmMachOp (MO_UU_Conv halfWordWidth wordWidth) [infoTableClosureType info_table]
where
info_table = infoTable (closureInfoPtr closure_ptr)
infoTable :: CmmExpr -> CmmExpr
infoTable info_ptr
| tablesNextToCode = cmmOffsetB info_ptr ( stdInfoTableSizeB)
| otherwise = cmmOffsetW info_ptr 1
infoTableConstrTag :: CmmExpr -> CmmExpr
infoTableConstrTag = infoTableSrtBitmap
infoTableSrtBitmap :: CmmExpr -> CmmExpr
infoTableSrtBitmap info_tbl
= CmmLoad (cmmOffsetB info_tbl stdSrtBitmapOffset) bHalfWord
infoTableClosureType :: CmmExpr -> CmmExpr
infoTableClosureType info_tbl
= CmmLoad (cmmOffsetB info_tbl stdClosureTypeOffset) bHalfWord
infoTablePtrs :: CmmExpr -> CmmExpr
infoTablePtrs info_tbl
= CmmLoad (cmmOffsetB info_tbl stdPtrsOffset) bHalfWord
infoTableNonPtrs :: CmmExpr -> CmmExpr
infoTableNonPtrs info_tbl
= CmmLoad (cmmOffsetB info_tbl stdNonPtrsOffset) bHalfWord
funInfoTable :: CmmExpr -> CmmExpr
funInfoTable info_ptr
| tablesNextToCode
= cmmOffsetB info_ptr ( stdInfoTableSizeB sIZEOF_StgFunInfoExtraRev)
| otherwise
= cmmOffsetW info_ptr (1 + stdInfoTableSizeW)