%
-% (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
-% Hans Wolfgang Loidl
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
+% $Id: Costs.lhs,v 1.33 2003/07/28 16:05:30 simonmar Exp $
+%
+% Only needed in a GranSim setup -- HWL
% ---------------------------------------------------------------------------
\section[Costs]{Evaluating the costs of computing some abstract C code}
instructions.
\end{itemize}
-This function is needed in GrAnSim for parallelism.
+This function is needed in GranSim for costing pieces of abstract C.
-These are first suggestions for scaling the costs. But, this scaling should be done in the RTS rather than the compiler (this really should be tunable!):
+These are first suggestions for scaling the costs. But, this scaling should
+be done in the RTS rather than the compiler (this really should be
+tunable!):
\begin{pseudocode}
#include "HsVersions.h"
import AbsCSyn
+import StgSyn ( StgOp(..) )
import PrimOp ( primOpNeedsWrapper, PrimOp(..) )
import Panic ( trace )
-- --------------------------------------------------------------------------
data CostRes = Cost (Int, Int, Int, Int, Int)
- deriving (Text)
+ deriving (Show)
nullCosts = Cost (0, 0, 0, 0, 0) :: CostRes
initHdrCosts = Cost (2, 0, 0, 1, 0) :: CostRes
-errorCosts = Cost (-1, -1, -1, -1, -1) -- just for debugging
-
-oneArithm = Cost (1, 0, 0, 0, 0) :: CostRes
instance Eq CostRes where
(==) t1 t2 = i && b && l && s && f
negate = mapOp negate
abs = mapOp abs
signum = mapOp signum
+ fromInteger _ = error "fromInteger not defined"
mapOp :: (Int -> Int) -> CostRes -> CostRes
mapOp g ( Cost (i, b, l, s, f) ) = Cost (g i, g b, g l, g s, g f)
-foldrOp :: (Int -> a -> a) -> a -> CostRes -> a
-foldrOp o x ( Cost (i1, b1, l1, s1, f1) ) =
- i1 `o` ( b1 `o` ( l1 `o` ( s1 `o` ( f1 `o` x))))
-
binOp :: (Int -> Int -> Int) -> CostRes -> CostRes -> CostRes
binOp o ( Cost (i1, b1, l1, s1, f1) ) ( Cost (i2, b2, l2, s2, f2) ) =
( Cost (i1 `o` i2, b1 `o` b2, l1 `o` l2, s1 `o` s2, f1 `o` f2) )
CCodeBlock _ absC -> costs absC
- CInitHdr cl_info reg_rel cost_centre -> initHdrCosts
+ CInitHdr cl_info reg_rel cost_centre _ -> initHdrCosts
{- This is more fancy but superflous: The addr modes
are fixed and so the costs are const!
For costing the args of this macro
see PprAbsC.lhs where args are inserted -}
- COpStmt modes_res primOp modes_args _ ->
+ COpStmt modes_res op modes_args _ ->
{-
let
n = length modes_res
-}
foldl (+) nullCosts [addrModeCosts mode Lhs | mode <- modes_res] +
foldl (+) nullCosts [addrModeCosts mode Rhs | mode <- modes_args] +
- primOpCosts primOp +
- if primOpNeedsWrapper primOp then SAVE_COSTS + RESTORE_COSTS
- else nullCosts
+ opCosts op
CSimultaneous absC -> costs absC
- CCheck _ amodes code -> Cost (2, 1, 0, 0, 0)
+ CCheck _ amodes code -> Cost (2, 1, 0, 0, 0) -- ToDo: refine this by
+ -- looking at the first arg
+
+ CRetDirect _ _ _ _ -> nullCosts
CMacroStmt macro modes -> stmtMacroCosts macro modes
-- *** the next three [or so...] are DATA (those above are CODE) ***
-- as they are data rather than code they all have nullCosts -- HWL
+ CCallTypedef _ _ _ _ _ -> nullCosts
+
CStaticClosure _ _ _ _ -> nullCosts
- CClosureInfoAndCode _ _ _ _ -> nullCosts
+ CSRT _ _ -> nullCosts
- CRetDirect _ _ _ _ -> nullCosts
+ CBitmap _ -> nullCosts
+
+ CClosureInfoAndCode _ _ -> nullCosts
CRetVector _ _ _ _ -> nullCosts
+ CClosureTbl _ -> nullCosts
+
CCostCentreDecl _ _ -> nullCosts
+
CCostCentreStackDecl _ -> nullCosts
CSplitMarker -> nullCosts
+ _ -> trace ("Costs.costs") nullCosts
+
+
-- ---------------------------------------------------------------------------
addrModeCosts :: CAddrMode -> Side -> CostRes
CVal _ _ -> if lhs then Cost (0, 0, 0, 1, 0)
else Cost (0, 0, 1, 0, 0)
- CReg _ -> nullCosts {- loading from, storing to reg is free ! -}
+ CAddr (CIndex _ n _ ) -> Cost (1, 0, 1, 0, 0) -- does pointer arithmetic
+
+ CAddr _ -> nullCosts
+
+ CReg _ -> nullCosts {- loading from, storing to reg is free ! -}
{- for costing CReg->Creg ops see special -}
{- case in costs fct -}
CLit _ -> if lhs then nullCosts -- should never occur
else Cost (1, 0, 0, 0, 0) -- typ.: mov lit,%reg
- CLitLit _ _ -> if lhs then nullCosts
- else Cost (1, 0, 0, 0, 0)
- -- same es CLit
-
CJoinPoint _ -> if lhs then Cost (0, 0, 0, 1, 0)
else Cost (0, 0, 1, 0, 0)
in
arg_costs +
case macro of
- ENTRY_CODE -> nullCosts
- ARG_TAG -> nullCosts -- XXX
- GET_TAG -> nullCosts -- XXX
-
+ ENTRY_CODE -> nullCosts -- nothing
+ ARG_TAG -> nullCosts -- nothing
+ GET_TAG -> Cost (0, 0, 1, 0, 0) -- indirect load
-- ---------------------------------------------------------------------------
stmtMacroCosts :: CStmtMacro -> [CAddrMode] -> CostRes
stmtMacroCosts macro modes =
- let
- arg_costs = foldl (+) nullCosts
- [addrModeCosts mode Rhs | mode <- modes]
- in
case macro of
- ARGS_CHK_LOAD_NODE -> Cost (2, 1, 0, 0, 0) {- StgMacros.lh -}
- -- p=probability of PAP (instead of AP): + p*(3,1,0,0,0)
- ARGS_CHK -> Cost (2, 1, 0, 0, 0) {- StgMacros.lh -}
UPD_CAF -> Cost (7, 0, 1, 3, 0) {- SMupdate.lh -}
UPD_BH_UPDATABLE -> Cost (3, 0, 0, 1, 0) {- SMupdate.lh -}
UPD_BH_SINGLE_ENTRY -> Cost (3, 0, 0, 1, 0) {- SMupdate.lh -}
- PUSH_UPD_FRAME -> Cost (3, 0, 0, 4, 0) {- SMupdate.lh -}
+ PUSH_UPD_FRAME -> Cost (3, 0, 0, 4, 0) {- Updates.h -}
SET_TAG -> nullCosts {- COptRegs.lh -}
GRAN_FETCH -> nullCosts {- GrAnSim bookkeeping -}
GRAN_RESCHEDULE -> nullCosts {- GrAnSim bookkeeping -}
gmpOps :: [PrimOp]
gmpOps =
[ IntegerAddOp , IntegerSubOp , IntegerMulOp
- , IntegerQuotRemOp , IntegerDivModOp , IntegerNegOp
+ , IntegerQuotRemOp , IntegerDivModOp
, IntegerCmpOp
, Integer2IntOp , Int2IntegerOp
- , Addr2IntegerOp
]
-abs_costs = nullCosts -- NB: This is normal STG code with costs already
- -- included; no need to add costs again.
-
umul_costs = Cost (21,4,0,0,0) -- due to spy counts
rem_costs = Cost (30,15,0,0,0) -- due to spy counts
div_costs = Cost (30,15,0,0,0) -- due to spy counts
-primOpCosts :: PrimOp -> CostRes
--- Special cases
-primOpCosts (CCallOp _ _ _ _) = SAVE_COSTS + RESTORE_COSTS
- -- don't guess costs of ccall proper
- -- for exact costing use a GRAN_EXEC
- -- in the C code
+-- ---------------------------------------------------------------------------
+
+opCosts :: StgOp -> CostRes
--- Usually 3 mov instructions are needed to get args and res in right place.
+opCosts (StgFCallOp _ _) = SAVE_COSTS + RESTORE_COSTS
+ -- Don't guess costs of ccall proper
+ -- for exact costing use a GRAN_EXEC in the C code
+
+opCosts (StgPrimOp primop)
+ = primOpCosts primop +
+ if primOpNeedsWrapper primop then SAVE_COSTS + RESTORE_COSTS
+ else nullCosts
+
+primOpCosts :: PrimOp -> CostRes
+-- Usually 3 mov instructions are needed to get args and res in right place.
primOpCosts IntMulOp = Cost (3, 1, 0, 0, 0) + umul_costs
primOpCosts IntQuotOp = Cost (3, 1, 0, 0, 0) + div_costs
primOpCosts IntRemOp = Cost (3, 1, 0, 0, 0) + rem_costs
primOpCosts IntNegOp = Cost (1, 1, 0, 0, 0) -- translates into 1 sub
-primOpCosts IntAbsOp = Cost (0, 1, 0, 0, 0) -- abs closure already costed
primOpCosts FloatGtOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
primOpCosts FloatGeOp = Cost (2, 0, 0, 0, 2) -- expensive f-comp
| primOp `elem` gmpOps = Cost (30, 5, 10, 10, 0) :: CostRes -- GUESS; check it
| otherwise = Cost (1, 0, 0, 0, 0)
--- ---------------------------------------------------------------------------
-{- HWL: currently unused
-
-costsByKind :: PrimRep -> Side -> CostRes
-
--- The following PrimKinds say that the data is already in a reg
-
-costsByKind CharRep _ = nullCosts
-costsByKind IntRep _ = nullCosts
-costsByKind WordRep _ = nullCosts
-costsByKind AddrRep _ = nullCosts
-costsByKind FloatRep _ = nullCosts
-costsByKind DoubleRep _ = nullCosts
--}
--- ---------------------------------------------------------------------------
\end{code}
-
-This is the data structure of {\tt PrimOp} copied from prelude/PrimOp.lhs.
-I include here some comments about the estimated costs for these @PrimOps@.
-Compare with the @primOpCosts@ fct above. -- HWL
-
-\begin{pseudocode}
-data PrimOp
- -- I assume all these basic comparisons take just one ALU instruction
- -- Checked that for Char, Int; Word, Addr should be the same as Int.
-
- = CharGtOp | CharGeOp | CharEqOp | CharNeOp | CharLtOp | CharLeOp
- | IntGtOp | IntGeOp | IntEqOp | IntNeOp | IntLtOp | IntLeOp
- | WordGtOp | WordGeOp | WordEqOp | WordNeOp | WordLtOp | WordLeOp
- | AddrGtOp | AddrGeOp | AddrEqOp | AddrNeOp | AddrLtOp | AddrLeOp
-
- -- Analogously, these take one FP unit instruction
- -- Haven't checked that, yet.
-
- | FloatGtOp | FloatGeOp | FloatEqOp | FloatNeOp | FloatLtOp | FloatLeOp
- | DoubleGtOp | DoubleGeOp | DoubleEqOp | DoubleNeOp | DoubleLtOp | DoubleLeOp
-
- -- 1 ALU op; unchecked
- | OrdOp | ChrOp
-
- -- these just take 1 ALU op; checked
- | IntAddOp | IntSubOp
-
- -- but these take more than that; see special cases in primOpCosts
- -- I counted the generated ass. instructions for these -> checked
- | IntMulOp | IntQuotOp
- | IntRemOp | IntNegOp | IntAbsOp
-
- -- Rest is unchecked so far -- HWL
-
- -- Word#-related ops:
- | AndOp | OrOp | NotOp | XorOp | ShiftLOp | ShiftROp
- | Int2WordOp | Word2IntOp -- casts
-
- -- Addr#-related ops:
- | Int2AddrOp | Addr2IntOp -- casts
-
- -- Float#-related ops:
- | FloatAddOp | FloatSubOp | FloatMulOp | FloatDivOp | FloatNegOp
- | Float2IntOp | Int2FloatOp
-
- | FloatExpOp | FloatLogOp | FloatSqrtOp
- | FloatSinOp | FloatCosOp | FloatTanOp
- | FloatAsinOp | FloatAcosOp | FloatAtanOp
- | FloatSinhOp | FloatCoshOp | FloatTanhOp
- -- not all machines have these available conveniently:
- -- | FloatAsinhOp | FloatAcoshOp | FloatAtanhOp
- | FloatPowerOp -- ** op
-
- -- Double#-related ops:
- | DoubleAddOp | DoubleSubOp | DoubleMulOp | DoubleDivOp | DoubleNegOp
- | Double2IntOp | Int2DoubleOp
- | Double2FloatOp | Float2DoubleOp
-
- | DoubleExpOp | DoubleLogOp | DoubleSqrtOp
- | DoubleSinOp | DoubleCosOp | DoubleTanOp
- | DoubleAsinOp | DoubleAcosOp | DoubleAtanOp
- | DoubleSinhOp | DoubleCoshOp | DoubleTanhOp
- -- not all machines have these available conveniently:
- -- | DoubleAsinhOp | DoubleAcoshOp | DoubleAtanhOp
- | DoublePowerOp -- ** op
-
- -- Integer (and related...) ops:
- -- slightly weird -- to match GMP package.
- | IntegerAddOp | IntegerSubOp | IntegerMulOp
- | IntegerQuotRemOp | IntegerDivModOp | IntegerNegOp
-
- | IntegerCmpOp
-
- | Integer2IntOp | Int2IntegerOp
- | Addr2IntegerOp -- "Addr" is *always* a literal string
- -- ?? gcd, etc?
-
- | FloatEncodeOp | FloatDecodeOp
- | DoubleEncodeOp | DoubleDecodeOp
-
- -- primitive ops for primitive arrays
-
- | NewArrayOp
- | NewByteArrayOp PrimRep
-
- | SameMutableArrayOp
- | SameMutableByteArrayOp
-
- | ReadArrayOp | WriteArrayOp | IndexArrayOp -- for arrays of Haskell ptrs
-
- | ReadByteArrayOp PrimRep
- | WriteByteArrayOp PrimRep
- | IndexByteArrayOp PrimRep
- | IndexOffAddrOp PrimRep
- -- PrimRep can be one of {Char,Int,Addr,Float,Double}Kind.
- -- This is just a cheesy encoding of a bunch of ops.
- -- Note that ForeignObjRep is not included -- the only way of
- -- creating a ForeignObj is with a ccall or casm.
-
- | UnsafeFreezeArrayOp | UnsafeFreezeByteArrayOp
-
- | MakeStablePtrOp | DeRefStablePtrOp
-\end{pseudocode}
-
-A special ``trap-door'' to use in making calls direct to C functions:
-Note: From GrAn point of view, CCall is probably very expensive
- The programmer can specify the costs of the Ccall by inserting
- a GRAN_EXEC(a,b,l,s,f) at the end of the C- code, specifing the
- number or arithm., branch, load, store and floating point instructions
- -- HWL
-
-\begin{pseudocode}
- | CCallOp String -- An "unboxed" ccall# to this named function
- Bool -- True <=> really a "casm"
- Bool -- True <=> might invoke Haskell GC
- [Type] -- Unboxed argument; the state-token
- -- argument will have been put *first*
- Type -- Return type; one of the "StateAnd<blah>#" types
-
- -- (... to be continued ... )
-\end{pseudocode}