summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2012-08-08 16:31:58 +0100
committerSimon Marlow <marlowsd@gmail.com>2012-08-09 09:08:58 +0100
commit09afcc9bbd35587d217d6cf42bd0635b26ee94ee (patch)
tree51e29e78c7e946605ebe5f44b55896418780fd27 /compiler
parent74d5ddeec2d02960815232b3bff63d669e6f7c50 (diff)
downloadhaskell-09afcc9bbd35587d217d6cf42bd0635b26ee94ee.tar.gz
Remove uses of fixC from the codeGen, and make the FCode monad strict
Diffstat (limited to 'compiler')
-rw-r--r--compiler/codeGen/StgCmm.hs21
-rw-r--r--compiler/codeGen/StgCmmBind.hs184
-rw-r--r--compiler/codeGen/StgCmmCon.hs71
-rw-r--r--compiler/codeGen/StgCmmEnv.hs28
-rw-r--r--compiler/codeGen/StgCmmExpr.hs48
-rw-r--r--compiler/codeGen/StgCmmMonad.hs74
6 files changed, 222 insertions, 204 deletions
diff --git a/compiler/codeGen/StgCmm.hs b/compiler/codeGen/StgCmm.hs
index d8127ab737..305c731ddf 100644
--- a/compiler/codeGen/StgCmm.hs
+++ b/compiler/codeGen/StgCmm.hs
@@ -124,25 +124,24 @@ variable. -}
cgTopBinding :: DynFlags -> (StgBinding,[(Id,[Id])]) -> FCode ()
cgTopBinding dflags (StgNonRec id rhs, _srts)
= do { id' <- maybeExternaliseId dflags id
- ; info <- cgTopRhs id' rhs
- ; addBindC (cg_id info) info -- Add the *un-externalised* Id to the envt,
+ ; (info, fcode) <- cgTopRhs id' rhs
+ ; fcode
+ ; addBindC (cg_id info) info -- Add the *un-externalised* Id to the envt,
-- so we find it when we look up occurrences
}
cgTopBinding dflags (StgRec pairs, _srts)
= do { let (bndrs, rhss) = unzip pairs
- ; bndrs' <- mapFCs (maybeExternaliseId dflags) bndrs
+ ; bndrs' <- Prelude.mapM (maybeExternaliseId dflags) bndrs
; let pairs' = zip bndrs' rhss
- ; fixC_(\ new_binds -> do
- { addBindsC new_binds
- ; mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs' })
- ; return () }
+ ; r <- sequence $ unzipWith cgTopRhs pairs'
+ ; let (infos, fcodes) = unzip r
+ ; addBindsC infos
+ ; sequence_ fcodes
+ }
--- Urgh! I tried moving the forkStatics call from the rhss of cgTopRhs
--- to enclose the listFCs in cgTopBinding, but that tickled the
--- statics "error" call in initC. I DON'T UNDERSTAND WHY!
-cgTopRhs :: Id -> StgRhs -> FCode CgIdInfo
+cgTopRhs :: Id -> StgRhs -> FCode (CgIdInfo, FCode ())
-- The Id is passed along for setting up a binding...
-- It's already been externalised if necessary
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
diff --git a/compiler/codeGen/StgCmmCon.hs b/compiler/codeGen/StgCmmCon.hs
index 23226bb45e..083e615b78 100644
--- a/compiler/codeGen/StgCmmCon.hs
+++ b/compiler/codeGen/StgCmmCon.hs
@@ -54,10 +54,18 @@ import Data.Char
cgTopRhsCon :: Id -- Name of thing bound to this RHS
-> DataCon -- Id
-> [StgArg] -- Args
- -> FCode CgIdInfo
+ -> FCode (CgIdInfo, FCode ())
cgTopRhsCon id con args
- = do {
- dflags <- getDynFlags
+ = return ( id_info, gen_code )
+ where
+ name = idName id
+ caffy = idCafInfo id -- any stgArgHasCafRefs args
+ closure_label = mkClosureLabel name caffy
+
+ id_info = litIdInfo id (mkConLFInfo con) (CmmLabel closure_label)
+
+ gen_code =
+ do { dflags <- getDynFlags
; when (platformOS (targetPlatform dflags) == OSMinGW32) $
-- Windows DLLs have a problem with static cross-DLL refs.
ASSERT( not (isDllConApp dflags con args) ) return ()
@@ -65,10 +73,6 @@ cgTopRhsCon id con args
-- LAY IT OUT
; let
- name = idName id
- caffy = idCafInfo id -- any stgArgHasCafRefs args
- closure_label = mkClosureLabel name caffy
-
(tot_wds, -- #ptr_wds + #nonptr_wds
ptr_wds, -- #ptr_wds
nv_args_w_offsets) = mkVirtConstrOffsets dflags (addArgReps args)
@@ -97,8 +101,7 @@ cgTopRhsCon id con args
-- BUILD THE OBJECT
; emitDataLits closure_label closure_rep
- -- RETURN
- ; return $ litIdInfo id (mkConLFInfo con) (CmmLabel closure_label) }
+ ; return () }
---------------------------------------------------------------
@@ -111,7 +114,7 @@ buildDynCon :: Id -- Name of the thing to which this constr will
-- current CCS if currentOrSubsumedCCS
-> DataCon -- The data constructor
-> [StgArg] -- Its args
- -> FCode (CgIdInfo, CmmAGraph)
+ -> FCode (CgIdInfo, FCode CmmAGraph)
-- Return details about how to find it and initialization code
buildDynCon binder cc con args
= do dflags <- getDynFlags
@@ -123,7 +126,7 @@ buildDynCon' :: DynFlags
-> CostCentreStack
-> DataCon
-> [StgArg]
- -> FCode (CgIdInfo, CmmAGraph)
+ -> FCode (CgIdInfo, FCode CmmAGraph)
{- We used to pass a boolean indicating whether all the
args were of size zero, so we could use a static
@@ -149,7 +152,7 @@ premature looking at the args will cause the compiler to black-hole!
buildDynCon' _ _ binder _cc con []
= return (litIdInfo binder (mkConLFInfo con)
(CmmLabel (mkClosureLabel (dataConName con) (idCafInfo binder))),
- mkNop)
+ return mkNop)
-------- buildDynCon': Charlike and Intlike constructors -----------
{- The following three paragraphs about @Char@-like and @Int@-like
@@ -188,7 +191,8 @@ buildDynCon' dflags platform binder _cc con [arg]
offsetW = (val_int - mIN_INTLIKE) * (fixedHdrSize dflags + 1)
-- INTLIKE closures consist of a header and one word payload
intlike_amode = cmmLabelOffW intlike_lbl offsetW
- ; return (litIdInfo binder (mkConLFInfo con) intlike_amode, mkNop) }
+ ; return ( litIdInfo binder (mkConLFInfo con) intlike_amode
+ , return mkNop) }
buildDynCon' dflags platform binder _cc con [arg]
| maybeCharLikeCon con
@@ -201,26 +205,33 @@ buildDynCon' dflags platform binder _cc con [arg]
offsetW = (val_int - mIN_CHARLIKE) * (fixedHdrSize dflags + 1)
-- CHARLIKE closures consist of a header and one word payload
charlike_amode = cmmLabelOffW charlike_lbl offsetW
- ; return (litIdInfo binder (mkConLFInfo con) charlike_amode, mkNop) }
+ ; return ( litIdInfo binder (mkConLFInfo con) charlike_amode
+ , return mkNop) }
-------- buildDynCon': the general case -----------
buildDynCon' dflags _ binder ccs con args
- = do { let (tot_wds, ptr_wds, args_w_offsets)
- = mkVirtConstrOffsets dflags (addArgReps args)
- -- No void args in args_w_offsets
- nonptr_wds = tot_wds - ptr_wds
- info_tbl = mkDataConInfoTable dflags con False ptr_wds nonptr_wds
- ; hp_plus_n <- allocDynClosure info_tbl lf_info
- use_cc blame_cc args_w_offsets
- ; regIdInfo binder lf_info hp_plus_n }
- where
- lf_info = mkConLFInfo con
-
- use_cc -- cost-centre to stick in the object
- | isCurrentCCS ccs = curCCS
- | otherwise = panic "buildDynCon: non-current CCS not implemented"
-
- blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
+ = do { (id_info, reg) <- rhsIdInfo binder lf_info
+ ; return (id_info, gen_code reg)
+ }
+ where
+ lf_info = mkConLFInfo con
+
+ gen_code reg
+ = do { let (tot_wds, ptr_wds, args_w_offsets)
+ = mkVirtConstrOffsets dflags (addArgReps args)
+ -- No void args in args_w_offsets
+ nonptr_wds = tot_wds - ptr_wds
+ info_tbl = mkDataConInfoTable dflags con False
+ ptr_wds nonptr_wds
+ ; hp_plus_n <- allocDynClosure info_tbl lf_info
+ use_cc blame_cc args_w_offsets
+ ; return (mkRhsInit reg lf_info hp_plus_n) }
+ where
+ use_cc -- cost-centre to stick in the object
+ | isCurrentCCS ccs = curCCS
+ | otherwise = panic "buildDynCon: non-current CCS not implemented"
+
+ blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
---------------------------------------------------------------
diff --git a/compiler/codeGen/StgCmmEnv.hs b/compiler/codeGen/StgCmmEnv.hs
index 4d91451628..9f1f161d37 100644
--- a/compiler/codeGen/StgCmmEnv.hs
+++ b/compiler/codeGen/StgCmmEnv.hs
@@ -18,7 +18,7 @@ module StgCmmEnv (
cgIdInfoId, cgIdInfoLF,
- litIdInfo, lneIdInfo, regIdInfo,
+ litIdInfo, lneIdInfo, rhsIdInfo, mkRhsInit,
idInfoToAmode,
NonVoid(..), isVoidId, nonVoidIds,
@@ -41,10 +41,10 @@ import StgCmmClosure
import CLabel
+import MkGraph
import BlockId
import CmmExpr
import CmmUtils
-import MkGraph (CmmAGraph, mkAssign)
import FastString
import Id
import VarEnv
@@ -89,26 +89,24 @@ litIdInfo id lf lit
where
tag = lfDynTag lf
-lneIdInfo :: Id -> [LocalReg] -> CgIdInfo
+lneIdInfo :: Id -> [NonVoid Id] -> CgIdInfo
lneIdInfo id regs
= CgIdInfo { cg_id = id, cg_lf = lf
- , cg_loc = LneLoc blk_id regs
+ , cg_loc = LneLoc blk_id (map idToReg regs)
, cg_tag = lfDynTag lf }
where
lf = mkLFLetNoEscape
blk_id = mkBlockId (idUnique id)
--- Because the register may be spilled to the stack in untagged form, we
--- modify the initialization code 'init' to immediately tag the
--- register, and store a plain register in the CgIdInfo. We allocate
--- a new register in order to keep single-assignment and help out the
--- inliner. -- EZY
-regIdInfo :: Id -> LambdaFormInfo -> CmmExpr -> FCode (CgIdInfo, CmmAGraph)
-regIdInfo id lf_info expr
- = do { reg <- newTemp (cmmExprType expr)
- ; let init = mkAssign (CmmLocal reg)
- (addDynTag expr (lfDynTag lf_info))
- ; return (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)), init) }
+
+rhsIdInfo :: Id -> LambdaFormInfo -> FCode (CgIdInfo, LocalReg)
+rhsIdInfo id lf_info
+ = do { reg <- newTemp gcWord
+ ; return (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)), reg) }
+
+mkRhsInit :: LocalReg -> LambdaFormInfo -> CmmExpr -> CmmAGraph
+mkRhsInit reg lf_info expr
+ = mkAssign (CmmLocal reg) (addDynTag expr (lfDynTag lf_info))
idInfoToAmode :: CgIdInfo -> CmmExpr
-- Returns a CmmExpr for the *tagged* pointer
diff --git a/compiler/codeGen/StgCmmExpr.hs b/compiler/codeGen/StgCmmExpr.hs
index cf3dc67dfc..038503eee7 100644
--- a/compiler/codeGen/StgCmmExpr.hs
+++ b/compiler/codeGen/StgCmmExpr.hs
@@ -45,13 +45,14 @@ import PrimOp
import TyCon
import Type
import CostCentre ( CostCentreStack, currentCCS )
-import Control.Monad (when)
import Maybes
import Util
import FastString
import Outputable
import UniqSupply
+import Control.Monad (when,void)
+
------------------------------------------------------------------------
-- cgExpr: the main function
------------------------------------------------------------------------
@@ -108,17 +109,17 @@ cgLneBinds :: BlockId -> StgBinding -> FCode ()
cgLneBinds join_id (StgNonRec bndr rhs)
= do { local_cc <- saveCurrentCostCentre
-- See Note [Saving the current cost centre]
- ; info <- cgLetNoEscapeRhs join_id local_cc bndr rhs
+ ; (info, fcode) <- cgLetNoEscapeRhs join_id local_cc bndr rhs
+ ; fcode
; addBindC (cg_id info) info }
cgLneBinds join_id (StgRec pairs)
= do { local_cc <- saveCurrentCostCentre
- ; new_bindings <- fixC (\ new_bindings -> do
- { addBindsC new_bindings
- ; listFCs [ cgLetNoEscapeRhs join_id local_cc b e
- | (b,e) <- pairs ] })
- ; addBindsC new_bindings }
-
+ ; r <- sequence $ unzipWith (cgLetNoEscapeRhs join_id local_cc) pairs
+ ; let (infos, fcodes) = unzip r
+ ; addBindsC infos
+ ; sequence_ fcodes
+ }
-------------------------
cgLetNoEscapeRhs
@@ -126,20 +127,21 @@ cgLetNoEscapeRhs
-> Maybe LocalReg -- Saved cost centre
-> Id
-> StgRhs
- -> FCode CgIdInfo
+ -> FCode (CgIdInfo, FCode ())
cgLetNoEscapeRhs join_id local_cc bndr rhs =
- do { (info, rhs_body) <- getCodeR $ cgLetNoEscapeRhsBody local_cc bndr rhs
+ do { (info, rhs_code) <- cgLetNoEscapeRhsBody local_cc bndr rhs
; let (bid, _) = expectJust "cgLetNoEscapeRhs" $ maybeLetNoEscape info
- ; emitOutOfLine bid $ rhs_body <*> mkBranch join_id
- ; return info
+ ; let code = do { body <- getCode rhs_code
+ ; emitOutOfLine bid (body <*> mkBranch join_id) }
+ ; return (info, code)
}
cgLetNoEscapeRhsBody
:: Maybe LocalReg -- Saved cost centre
-> Id
-> StgRhs
- -> FCode CgIdInfo
+ -> FCode (CgIdInfo, FCode ())
cgLetNoEscapeRhsBody local_cc bndr (StgRhsClosure cc _bi _ _upd _ args body)
= cgLetNoEscapeClosure bndr local_cc cc (nonVoidIds args) body
cgLetNoEscapeRhsBody local_cc bndr (StgRhsCon cc con args)
@@ -156,17 +158,18 @@ cgLetNoEscapeClosure
-> CostCentreStack -- XXX: *** NOT USED *** why not?
-> [NonVoid Id] -- Args (as in \ args -> body)
-> StgExpr -- Body (as in above)
- -> FCode CgIdInfo
+ -> FCode (CgIdInfo, FCode ())
cgLetNoEscapeClosure bndr cc_slot _unused_cc args body
- = do { arg_regs <- forkProc $ do
- { restoreCurrentCostCentre cc_slot
- ; arg_regs <- bindArgsToRegs args
- ; _ <- altHeapCheck arg_regs (cgExpr body)
+ = return ( lneIdInfo bndr args
+ , code )
+ where
+ code = forkProc $ do
+ { restoreCurrentCostCentre cc_slot
+ ; arg_regs <- bindArgsToRegs args
+ ; void $ altHeapCheck arg_regs (cgExpr body) }
-- Using altHeapCheck just reduces
-- instructions to save on stack
- ; return arg_regs }
- ; return $ lneIdInfo bndr arg_regs}
------------------------------------------------------------------------
@@ -600,11 +603,12 @@ cgConApp con stg_args
| otherwise -- Boxed constructors; allocate and return
= ASSERT( stg_args `lengthIs` dataConRepRepArity con )
- do { (idinfo, init) <- buildDynCon (dataConWorkId con) currentCCS con stg_args
+ do { (idinfo, fcode_init) <- buildDynCon (dataConWorkId con)
+ currentCCS con stg_args
-- The first "con" says that the name bound to this closure is
-- is "con", which is a bit of a fudge, but it only affects profiling
- ; emit init
+ ; emit =<< fcode_init
; emitReturn [idInfoToAmode idinfo] }
diff --git a/compiler/codeGen/StgCmmMonad.hs b/compiler/codeGen/StgCmmMonad.hs
index 1819e44bb6..2290914310 100644
--- a/compiler/codeGen/StgCmmMonad.hs
+++ b/compiler/codeGen/StgCmmMonad.hs
@@ -17,8 +17,8 @@
module StgCmmMonad (
FCode, -- type
- initC, runC, thenC, thenFC, listCs, listFCs, mapCs, mapFCs,
- returnFC, fixC, fixC_, nopC, whenC,
+ initC, runC, thenC, thenFC, listCs,
+ returnFC, nopC, whenC,
newUnique, newUniqSupply,
newLabelC, emitLabel,
@@ -93,10 +93,10 @@ infixr 9 `thenFC`
-- The FCode monad and its types
--------------------------------------------------------
-newtype FCode a = FCode (CgInfoDownwards -> CgState -> (a, CgState))
+newtype FCode a = FCode (CgInfoDownwards -> CgState -> (# a, CgState #))
instance Functor FCode where
- fmap f (FCode g) = FCode $ \i s -> let (a,s') = g i s in (f a, s')
+ fmap f (FCode g) = FCode $ \i s -> case g i s of (# a, s' #) -> (# f a, s' #)
instance Monad FCode where
(>>=) = thenFC
@@ -111,15 +111,15 @@ initC = do { uniqs <- mkSplitUniqSupply 'c'
; return (initCgState uniqs) }
runC :: DynFlags -> Module -> CgState -> FCode a -> (a,CgState)
-runC dflags mod st (FCode code) = code (initCgInfoDown dflags mod) st
+runC dflags mod st fcode = doFCode fcode (initCgInfoDown dflags mod) st
returnFC :: a -> FCode a
-returnFC val = FCode (\_info_down state -> (val, state))
+returnFC val = FCode (\_info_down state -> (# val, state #))
thenC :: FCode () -> FCode a -> FCode a
thenC (FCode m) (FCode k) =
- FCode (\info_down state -> let (_,new_state) = m info_down state in
- k info_down new_state)
+ FCode $ \info_down state -> case m info_down state of
+ (# _,new_state #) -> k info_down new_state
nopC :: FCode ()
nopC = return ()
@@ -134,45 +134,13 @@ listCs (fc:fcs) = do
fc
listCs fcs
-mapCs :: (a -> FCode ()) -> [a] -> FCode ()
-mapCs = mapM_
-
-thenFC :: FCode a -> (a -> FCode c) -> FCode c
-thenFC (FCode m) k = FCode (
+thenFC :: FCode a -> (a -> FCode c) -> FCode c
+thenFC (FCode m) k = FCode $
\info_down state ->
- let
- (m_result, new_state) = m info_down state
- (FCode kcode) = k m_result
- in
- kcode info_down new_state
- )
- -- Note: this is a lazy monad. We can't easily make it strict due
- -- to the use of fixC for compiling recursive bindings (see Note
- -- [cgBind rec]). cgRhs returns a CgIdInfo which is fed back in
- -- via the CgBindings, and making the monad strict means that we
- -- can't look at the CgIdInfo too early. Things seem to just
- -- about work when the monad is lazy. I hate this stuff --SDM
-
-
-listFCs :: [FCode a] -> FCode [a]
-listFCs = Prelude.sequence
-
-mapFCs :: (a -> FCode b) -> [a] -> FCode [b]
-mapFCs = mapM
-
-fixC :: (a -> FCode a) -> FCode a
-fixC fcode = FCode (
- \info_down state ->
- let
- FCode fc = fcode v
- result@(v,_) = fc info_down state
- -- ^--------^
- in
- result
- )
-
-fixC_ :: (a -> FCode a) -> FCode ()
-fixC_ fcode = fixC fcode >> return ()
+ case m info_down state of
+ (# m_result, new_state #) ->
+ case k m_result of
+ FCode kcode -> kcode info_down new_state
--------------------------------------------------------
-- The code generator environment
@@ -405,10 +373,10 @@ hp_usg `maxHpHw` hw = hp_usg { virtHp = virtHp hp_usg `max` hw }
--------------------------------------------------------
getState :: FCode CgState
-getState = FCode $ \_info_down state -> (state,state)
+getState = FCode $ \_info_down state -> (# state, state #)
setState :: CgState -> FCode ()
-setState state = FCode $ \_info_down _ -> ((),state)
+setState state = FCode $ \_info_down _ -> (# (), state #)
getHpUsage :: FCode HeapUsage
getHpUsage = do
@@ -452,7 +420,8 @@ getStaticBinds = do
withState :: FCode a -> CgState -> FCode (a,CgState)
withState (FCode fcode) newstate = FCode $ \info_down state ->
- let (retval, state2) = fcode info_down newstate in ((retval,state2), state)
+ case fcode info_down newstate of
+ (# retval, state2 #) -> (# (retval,state2), state #)
newUniqSupply :: FCode UniqSupply
newUniqSupply = do
@@ -468,7 +437,7 @@ newUnique = do
------------------
getInfoDown :: FCode CgInfoDownwards
-getInfoDown = FCode $ \info_down state -> (info_down,state)
+getInfoDown = FCode $ \info_down state -> (# info_down,state #)
instance HasDynFlags FCode where
getDynFlags = liftM cgd_dflags getInfoDown
@@ -480,8 +449,9 @@ withInfoDown :: FCode a -> CgInfoDownwards -> FCode a
withInfoDown (FCode fcode) info_down = FCode $ \_ state -> fcode info_down state
doFCode :: FCode a -> CgInfoDownwards -> CgState -> (a,CgState)
-doFCode (FCode fcode) info_down state = fcode info_down state
-
+doFCode (FCode fcode) info_down state =
+ case fcode info_down state of
+ (# a, s #) -> ( a, s )
-- ----------------------------------------------------------------------------
-- Get the current module name