summaryrefslogtreecommitdiff
path: root/compiler/codeGen/StgCmmBind.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/codeGen/StgCmmBind.hs')
-rw-r--r--compiler/codeGen/StgCmmBind.hs184
1 files changed, 110 insertions, 74 deletions
diff --git a/compiler/codeGen/StgCmmBind.hs b/compiler/codeGen/StgCmmBind.hs
index 5aec9e3bbe..0e78eaf1fa 100644
--- a/compiler/codeGen/StgCmmBind.hs
+++ b/compiler/codeGen/StgCmmBind.hs
@@ -69,32 +69,37 @@ cgTopRhsClosure :: Id
-> UpdateFlag
-> [Id] -- Args
-> StgExpr
- -> FCode CgIdInfo
-
-cgTopRhsClosure id ccs _ upd_flag args body = do
- { -- LAY OUT THE OBJECT
- let name = idName id
- ; lf_info <- mkClosureLFInfo id TopLevel [] upd_flag args
- ; mod_name <- getModuleName
- ; dflags <- getDynFlags
- ; let descr = closureDescription dflags mod_name name
- closure_info = mkClosureInfo dflags True id lf_info 0 0 descr
- closure_label = mkLocalClosureLabel name (idCafInfo id)
- cg_id_info = litIdInfo id lf_info (CmmLabel closure_label)
- caffy = idCafInfo id
- info_tbl = mkCmmInfo closure_info -- XXX short-cut
- closure_rep = mkStaticClosureFields dflags info_tbl ccs caffy []
-
- -- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)
- ; emitDataLits closure_label closure_rep
- ; let fv_details :: [(NonVoid Id, VirtualHpOffset)]
- (_, _, fv_details) = mkVirtHeapOffsets dflags (isLFThunk lf_info)
- (addIdReps [])
- -- Don't drop the non-void args until the closure info has been made
- ; forkClosureBody (closureCodeBody True id closure_info ccs
- (nonVoidIds args) (length args) body fv_details)
-
- ; returnFC cg_id_info }
+ -> FCode (CgIdInfo, FCode ())
+
+cgTopRhsClosure id ccs _ upd_flag args body
+ = do { lf_info <- mkClosureLFInfo id TopLevel [] upd_flag args
+ ; let closure_label = mkLocalClosureLabel (idName id) (idCafInfo id)
+ cg_id_info = litIdInfo id lf_info (CmmLabel closure_label)
+ ; return (cg_id_info, gen_code lf_info closure_label)
+ }
+ where
+ gen_code lf_info closure_label
+ = do { -- LAY OUT THE OBJECT
+ let name = idName id
+ ; mod_name <- getModuleName
+ ; dflags <- getDynFlags
+ ; let descr = closureDescription dflags mod_name name
+ closure_info = mkClosureInfo dflags True id lf_info 0 0 descr
+
+ caffy = idCafInfo id
+ info_tbl = mkCmmInfo closure_info -- XXX short-cut
+ closure_rep = mkStaticClosureFields dflags info_tbl ccs caffy []
+
+ -- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)
+ ; emitDataLits closure_label closure_rep
+ ; let fv_details :: [(NonVoid Id, VirtualHpOffset)]
+ (_, _, fv_details) = mkVirtHeapOffsets dflags (isLFThunk lf_info)
+ (addIdReps [])
+ -- Don't drop the non-void args until the closure info has been made
+ ; forkClosureBody (closureCodeBody True id closure_info ccs
+ (nonVoidIds args) (length args) body fv_details)
+
+ ; return () }
------------------------------------------------------------------------
-- Non-top-level bindings
@@ -102,25 +107,30 @@ cgTopRhsClosure id ccs _ upd_flag args body = do
cgBind :: StgBinding -> FCode ()
cgBind (StgNonRec name rhs)
- = do { ((info, init), body) <- getCodeR $ cgRhs name rhs
+ = do { (info, fcode) <- cgRhs name rhs
; addBindC (cg_id info) info
- ; emit (body <*> init) }
+ ; init <- fcode
+ ; emit init
+ }
-- init cannot be used in body, so slightly better to sink it eagerly
cgBind (StgRec pairs)
- = do { ((new_binds, inits), body) <- getCodeR $ fixC (\ new_binds_inits ->
- do { addBindsC $ fst new_binds_inits -- avoid premature deconstruction
- ; liftM unzip $ listFCs [ cgRhs b e | (b,e) <- pairs ] })
- ; addBindsC new_binds
- ; emit (catAGraphs inits <*> body) }
+ = do { r <- sequence $ unzipWith cgRhs pairs
+ ; let (id_infos, fcodes) = unzip r
+ ; addBindsC id_infos
+ ; (inits, body) <- getCodeR $ sequence fcodes
+ ; emit (catAGraphs inits <*> body) }
{- Note [cgBind rec]
+
Recursive let-bindings are tricky.
Consider the following pseudocode:
+
let x = \_ -> ... y ...
y = \_ -> ... z ...
z = \_ -> ... x ...
in ...
+
For each binding, we need to allocate a closure, and each closure must
capture the address of the other closures.
We want to generate the following C-- code:
@@ -139,24 +149,40 @@ cgBind (StgRec pairs)
...
For each closure, we must generate not only the code to allocate and
- initialize the closure itself, but also some Initialization Code that
+ initialize the closure itself, but also some initialization Code that
sets a variable holding the closure pointer.
- The complication here is that we don't know the heap offsets a priori,
- which has two consequences:
- 1. we need a fixpoint
- 2. we can't trivially separate the Initialization Code from the
- code that compiles the right-hand-sides
-
- Note: We don't need this complication with let-no-escapes, because
- in that case, the names are bound to labels in the environment,
- and we don't need to emit any code to witness that binding.
--}
---------------------
-cgRhs :: Id -> StgRhs -> FCode (CgIdInfo, CmmAGraph)
- -- The Id is passed along so a binding can be set up
- -- The returned values are the binding for the environment
- -- and the Initialization Code that witnesses the binding
+ We could generate a pair of the (init code, body code), but since
+ the bindings are recursive we also have to initialise the
+ environment with the CgIdInfo for all the bindings before compiling
+ anything. So we do this in 3 stages:
+
+ 1. collect all the CgIdInfos and initialise the environment
+ 2. compile each binding into (init, body) code
+ 3. emit all the inits, and then all the bodies
+
+ We'd rather not have separate functions to do steps 1 and 2 for
+ each binding, since in pratice they share a lot of code. So we
+ have just one function, cgRhs, that returns a pair of the CgIdInfo
+ for step 1, and a monadic computation to generate the code in step
+ 2.
+
+ The alternative to separating things in this way is to use a
+ fixpoint. That's what we used to do, but it introduces a
+ maintenance nightmare because there is a subtle dependency on not
+ being too strict everywhere. Doing things this way means that the
+ FCode monad can be strict, for example.
+ -}
+
+cgRhs :: Id
+ -> StgRhs
+ -> FCode (
+ CgIdInfo -- The info for this binding
+ , FCode CmmAGraph -- A computation which will generate the
+ -- code for the binding, and return an
+ -- assignent of the form "x = Hp - n"
+ -- (see above)
+ )
cgRhs name (StgRhsCon cc con args)
= buildDynCon name cc con args
@@ -174,7 +200,7 @@ mkRhsClosure :: DynFlags -> Id -> CostCentreStack -> StgBinderInfo
-> UpdateFlag
-> [Id] -- Args
-> StgExpr
- -> FCode (CgIdInfo, CmmAGraph)
+ -> FCode (CgIdInfo, FCode CmmAGraph)
{- mkRhsClosure looks for two special forms of the right-hand side:
a) selector thunks
@@ -212,11 +238,11 @@ for semi-obvious reasons.
-}
---------- Note [Selectors] ------------------
-mkRhsClosure dflags bndr cc bi
+mkRhsClosure dflags bndr _cc _bi
[NonVoid the_fv] -- Just one free var
upd_flag -- Updatable thunk
[] -- A thunk
- body@(StgCase (StgApp scrutinee [{-no args-}])
+ (StgCase (StgApp scrutinee [{-no args-}])
_ _ _ _ -- ignore uniq, etc.
(AlgAlt _)
[(DataAlt _, params, _use_mask,
@@ -232,7 +258,7 @@ mkRhsClosure dflags bndr cc bi
-- will evaluate to.
--
-- srt is discarded; it must be empty
- cgStdThunk bndr cc bi body lf_info [StgVarArg the_fv]
+ cgRhsStdThunk bndr lf_info [StgVarArg the_fv]
where
lf_info = mkSelectorLFInfo bndr offset_into_int
(isUpdatable upd_flag)
@@ -243,11 +269,11 @@ mkRhsClosure dflags bndr cc bi
offset_into_int = the_offset - fixedHdrSize dflags
---------- Note [Ap thunks] ------------------
-mkRhsClosure dflags bndr cc bi
+mkRhsClosure dflags bndr _cc _bi
fvs
upd_flag
[] -- No args; a thunk
- body@(StgApp fun_id args)
+ (StgApp fun_id args)
| args `lengthIs` (arity-1)
&& all (isGcPtrRep . idPrimRep . stripNV) fvs
@@ -259,7 +285,8 @@ mkRhsClosure dflags bndr cc bi
-- thunk (e.g. its type) (#949)
-- Ha! an Ap thunk
- = cgStdThunk bndr cc bi body lf_info payload
+ = cgRhsStdThunk bndr lf_info payload
+
where
lf_info = mkApLFInfo bndr upd_flag arity
-- the payload has to be in the correct order, hence we can't
@@ -269,7 +296,12 @@ mkRhsClosure dflags bndr cc bi
---------- Default case ------------------
mkRhsClosure _ bndr cc _ fvs upd_flag args body
- = do { -- LAY OUT THE OBJECT
+ = do { lf_info <- mkClosureLFInfo bndr NotTopLevel fvs upd_flag args
+ ; (id_info, reg) <- rhsIdInfo bndr lf_info
+ ; return (id_info, gen_code lf_info reg) }
+ where
+ gen_code lf_info reg
+ = do { -- LAY OUT THE OBJECT
-- If the binder is itself a free variable, then don't store
-- it in the closure. Instead, just bind it to Node on entry.
-- NB we can be sure that Node will point to it, because we
@@ -285,8 +317,7 @@ mkRhsClosure _ bndr cc _ fvs upd_flag args body
-- MAKE CLOSURE INFO FOR THIS CLOSURE
- ; lf_info <- mkClosureLFInfo bndr NotTopLevel fvs upd_flag args
- ; mod_name <- getModuleName
+ ; mod_name <- getModuleName
; dflags <- getDynFlags
; let name = idName bndr
descr = closureDescription dflags mod_name name
@@ -316,23 +347,26 @@ mkRhsClosure _ bndr cc _ fvs upd_flag args body
(map toVarArg fv_details)
-- RETURN
- ; regIdInfo bndr lf_info hp_plus_n }
+ ; return (mkRhsInit reg lf_info hp_plus_n) }
+
-- Use with care; if used inappropriately, it could break invariants.
stripNV :: NonVoid a -> a
stripNV (NonVoid a) = a
-------------------------
-cgStdThunk
- :: Id
- -> CostCentreStack -- Optional cost centre annotation
- -> StgBinderInfo -- XXX: not used??
- -> StgExpr
- -> LambdaFormInfo
- -> [StgArg] -- payload
- -> FCode (CgIdInfo, CmmAGraph)
-
-cgStdThunk bndr _cc _bndr_info _body lf_info payload
+cgRhsStdThunk
+ :: Id
+ -> LambdaFormInfo
+ -> [StgArg] -- payload
+ -> FCode (CgIdInfo, FCode CmmAGraph)
+
+cgRhsStdThunk bndr lf_info payload
+ = do { (id_info, reg) <- rhsIdInfo bndr lf_info
+ ; return (id_info, gen_code reg)
+ }
+ where
+ gen_code reg
= do -- AHA! A STANDARD-FORM THUNK
{ -- LAY OUT THE OBJECT
mod_name <- getModuleName
@@ -354,7 +388,8 @@ cgStdThunk bndr _cc _bndr_info _body lf_info payload
use_cc blame_cc payload_w_offsets
-- RETURN
- ; regIdInfo bndr lf_info hp_plus_n }
+ ; return (mkRhsInit reg lf_info hp_plus_n) }
+
mkClosureLFInfo :: Id -- The binder
-> TopLevelFlag -- True of top level
@@ -364,8 +399,9 @@ mkClosureLFInfo :: Id -- The binder
-> FCode LambdaFormInfo
mkClosureLFInfo bndr top fvs upd_flag args
| null args = return (mkLFThunk (idType bndr) top (map stripNV fvs) upd_flag)
- | otherwise = do { arg_descr <- mkArgDescr (idName bndr) args
- ; return (mkLFReEntrant top (map stripNV fvs) args arg_descr) }
+ | otherwise =
+ do { arg_descr <- mkArgDescr (idName bndr) args
+ ; return (mkLFReEntrant top (map stripNV fvs) args arg_descr) }
------------------------------------------------------------------------
@@ -451,7 +487,7 @@ bind_fv :: (NonVoid Id, VirtualHpOffset) -> FCode (LocalReg, WordOff)
bind_fv (id, off) = do { reg <- rebindToReg id; return (reg, off) }
load_fvs :: LocalReg -> LambdaFormInfo -> [(LocalReg, WordOff)] -> FCode ()
-load_fvs node lf_info = mapCs (\ (reg, off) ->
+load_fvs node lf_info = mapM_ (\ (reg, off) ->
emit $ mkTaggedObjectLoad reg node off tag)
where tag = lfDynTag lf_info