summaryrefslogtreecommitdiff
path: root/ghc/compiler/profiling/SCCfinal.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/profiling/SCCfinal.lhs')
-rw-r--r--ghc/compiler/profiling/SCCfinal.lhs445
1 files changed, 445 insertions, 0 deletions
diff --git a/ghc/compiler/profiling/SCCfinal.lhs b/ghc/compiler/profiling/SCCfinal.lhs
new file mode 100644
index 0000000000..06d4663685
--- /dev/null
+++ b/ghc/compiler/profiling/SCCfinal.lhs
@@ -0,0 +1,445 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[SCCfinal]{Modify and collect code generation for final StgProgram}
+
+This is now a sort-of-normal STG-to-STG pass (WDP 94/06), run by stg2stg.
+
+* Traverses the STG program collecting the cost centres. These are
+ required to declare the cost centres at the start of code
+ generation.
+
+ Note: because of cross-module unfolding, some of these cost centres
+ may be from other modules. But will still have to give them
+ "extern" declarations.
+
+* Puts on CAF cost-centres if the user has asked for individual CAF
+ cost-centres.
+
+* Ditto for individual DICT cost-centres.
+
+* Boxes top-level inherited functions passed as arguments.
+
+* "Distributes" given cost-centres to all as-yet-unmarked RHSs.
+
+\begin{code}
+#include "HsVersions.h"
+
+module SCCfinal ( stgMassageForProfiling ) where
+
+import Pretty -- ToDo: rm (debugging only)
+
+import AbsUniType ( isDictTy, getUniDataTyCon_maybe,
+ isTupleTyCon, isFunType, getTauType,
+ splitType -- pragmas
+ )
+import CmdLineOpts
+import CostCentre
+import Id ( mkSysLocal, getIdUniType )
+import SrcLoc ( mkUnknownSrcLoc )
+import StgSyn
+import SplitUniq
+import UniqSet ( emptyUniqSet
+ IF_ATTACK_PRAGMAS(COMMA emptyUFM)
+ )
+import Unique
+import Util
+
+infixr 9 `thenMM`, `thenMM_`
+\end{code}
+
+\begin{code}
+type CollectedCCs = ([CostCentre], -- locally defined ones
+ [CostCentre]) -- ones needing "extern" decls
+
+stgMassageForProfiling
+ :: FAST_STRING -> FAST_STRING -- module name, group name
+ -> SplitUniqSupply -- unique supply
+ -> (GlobalSwitch -> Bool) -- command-line opts checker
+ -> [PlainStgBinding] -- input
+ -> (CollectedCCs, [PlainStgBinding])
+
+stgMassageForProfiling mod_name grp_name us sw_chkr stg_binds
+ = let
+ ((local_ccs, extern_ccs),
+ stg_binds2)
+ = initMM mod_name us (mapMM do_top_binding stg_binds)
+
+ fixed_ccs
+ = if do_auto_sccs_on_cafs || doing_prelude
+ then [] -- don't need "all CAFs" CC (for Prelude, we use PreludeCC)
+ else [all_cafs_cc]
+
+ local_ccs_no_dups = fst (removeDups cmpCostCentre local_ccs)
+ extern_ccs_no_dups = fst (removeDups cmpCostCentre extern_ccs)
+ in
+ ((fixed_ccs ++ local_ccs_no_dups, extern_ccs_no_dups), stg_binds2)
+ where
+ do_auto_sccs_on_cafs = sw_chkr AutoSccsOnIndividualCafs -- only use!
+--UNUSED: do_auto_sccs_on_dicts = sw_chkr AutoSccsOnIndividualDicts -- only use! ** UNUSED really **
+ doing_prelude = sw_chkr CompilingPrelude
+
+ all_cafs_cc = if doing_prelude
+ then preludeCafsCostCentre
+ else mkAllCafsCC mod_name grp_name
+
+ ----------
+ do_top_binding :: PlainStgBinding -> MassageM PlainStgBinding
+
+ do_top_binding (StgNonRec b rhs)
+ = do_top_rhs b rhs `thenMM` \ rhs' ->
+ returnMM (StgNonRec b rhs')
+
+ do_top_binding (StgRec pairs)
+ = mapMM do_pair pairs `thenMM` \ pairs2 ->
+ returnMM (StgRec pairs2)
+ where
+ do_pair (b, rhs)
+ = do_top_rhs b rhs `thenMM` \ rhs2 ->
+ returnMM (b, rhs2)
+
+ ----------
+ do_top_rhs :: Id -> PlainStgRhs -> MassageM PlainStgRhs
+
+ do_top_rhs binder (StgRhsClosure rhs_cc bi fv u [] (StgSCC ty cc (StgConApp con args lvs)))
+ -- top-level _scc_ around nothing but static data; toss it -- it's pointless
+ = returnMM (StgRhsCon dontCareCostCentre con args)
+
+ do_top_rhs binder (StgRhsClosure rhs_cc bi fv u [] (StgSCC ty cc expr))
+-- OLD:
+-- | noCostCentreAttached rhs_cc || currentOrSubsumedCosts rhs_cc
+-- -- doubtful guard... ToDo?
+ -- Top level CAF with explicit scc expression. Attach CAF
+ -- cost centre to StgRhsClosure and collect.
+ = let
+ calved_cc = cafifyCC cc
+ in
+ collectCC calved_cc `thenMM_`
+ set_prevailing_cc calved_cc (
+ do_expr expr
+ ) `thenMM` \ expr' ->
+ returnMM (StgRhsClosure calved_cc bi fv u [] expr')
+
+ do_top_rhs binder (StgRhsClosure cc bi fv u [] body)
+ | noCostCentreAttached cc || currentOrSubsumedCosts cc
+ -- Top level CAF without a cost centre attached: Collect
+ -- cost centre with binder name, if collecting CAFs.
+ = let
+ (did_something, cc2)
+ = if do_auto_sccs_on_cafs then
+ (True, mkAutoCC binder mod_name grp_name IsCafCC)
+ else
+ (False, all_cafs_cc)
+ in
+ (if did_something
+ then collectCC cc2
+ else nopMM) `thenMM_`
+ set_prevailing_cc cc2 (
+ do_expr body
+ ) `thenMM` \body2 ->
+ returnMM (StgRhsClosure cc2 bi fv u [] body2)
+
+ do_top_rhs binder (StgRhsClosure _ bi fv u args body@(StgSCC ty cc expr))
+ -- We blindly use the cc off the _scc_
+ = set_prevailing_cc cc (
+ do_expr body
+ ) `thenMM` \ body2 ->
+ returnMM (StgRhsClosure cc bi fv u args body2)
+
+ do_top_rhs binder (StgRhsClosure cc bi fv u args body)
+ = let
+ cc2 = if noCostCentreAttached cc
+ then subsumedCosts -- it's not a thunk; it is top-level & arity > 0
+ else cc
+ in
+ set_prevailing_cc cc2 (
+ do_expr body
+ ) `thenMM` \ body' ->
+ returnMM (StgRhsClosure cc2 bi fv u args body')
+
+ do_top_rhs binder (StgRhsCon cc con args)
+ = returnMM (StgRhsCon dontCareCostCentre con args)
+ -- Top-level (static) data is not counted in heap
+ -- profiles; nor do we set CCC from it; so we
+ -- just slam in dontCareCostCentre
+
+ ------
+ do_expr :: PlainStgExpr -> MassageM PlainStgExpr
+
+ do_expr (StgApp fn args lvs)
+ = boxHigherOrderArgs (StgApp fn) args lvs
+
+ do_expr (StgConApp con args lvs)
+ = boxHigherOrderArgs (StgConApp con) args lvs
+
+ do_expr (StgPrimApp op args lvs)
+ = boxHigherOrderArgs (StgPrimApp op) args lvs
+
+ do_expr (StgSCC ty cc expr) -- Ha, we found a cost centre!
+ = collectCC cc `thenMM_`
+ set_prevailing_cc cc (
+ do_expr expr
+ ) `thenMM` \ expr' ->
+ returnMM (StgSCC ty cc expr')
+
+ do_expr (StgCase expr fv1 fv2 uniq alts)
+ = do_expr expr `thenMM` \ expr' ->
+ do_alts alts `thenMM` \ alts' ->
+ returnMM (StgCase expr' fv1 fv2 uniq alts')
+ where
+ do_alts (StgAlgAlts ty alts def)
+ = mapMM do_alt alts `thenMM` \ alts' ->
+ do_deflt def `thenMM` \ def' ->
+ returnMM (StgAlgAlts ty alts' def')
+ where
+ do_alt (id, bs, use_mask, e)
+ = do_expr e `thenMM` \ e' ->
+ returnMM (id, bs, use_mask, e')
+
+ do_alts (StgPrimAlts ty alts def)
+ = mapMM do_alt alts `thenMM` \ alts' ->
+ do_deflt def `thenMM` \ def' ->
+ returnMM (StgPrimAlts ty alts' def')
+ where
+ do_alt (l,e)
+ = do_expr e `thenMM` \ e' ->
+ returnMM (l,e')
+
+ do_deflt StgNoDefault = returnMM StgNoDefault
+ do_deflt (StgBindDefault b is_used e)
+ = do_expr e `thenMM` \ e' ->
+ returnMM (StgBindDefault b is_used e')
+
+ do_expr (StgLet b e)
+ = set_prevailing_cc_maybe useCurrentCostCentre (
+ do_binding b `thenMM` \ b' ->
+ do_expr e `thenMM` \ e' ->
+ returnMM (StgLet b' e') )
+
+ do_expr (StgLetNoEscape lvs1 lvs2 rhs body)
+ = set_prevailing_cc_maybe useCurrentCostCentre (
+ do_binding rhs `thenMM` \ rhs' ->
+ do_expr body `thenMM` \ body' ->
+ returnMM (StgLetNoEscape lvs1 lvs2 rhs' body') )
+
+ ----------
+ do_binding :: PlainStgBinding -> MassageM PlainStgBinding
+
+ do_binding (StgNonRec b rhs)
+ = do_rhs rhs `thenMM` \ rhs' ->
+ returnMM (StgNonRec b rhs')
+
+ do_binding (StgRec pairs)
+ = mapMM do_pair pairs `thenMM` \ new_pairs ->
+ returnMM (StgRec new_pairs)
+ where
+ do_pair (b, rhs)
+ = do_rhs rhs `thenMM` \ rhs' ->
+ returnMM (b, rhs')
+
+ do_rhs :: PlainStgRhs -> MassageM PlainStgRhs
+ -- We play much the same game as we did in do_top_rhs above;
+ -- but we don't have to worry about cafifying, etc.
+ -- (ToDo: consolidate??)
+
+{- Patrick says NO: it will mess up our counts (WDP 95/07)
+ do_rhs (StgRhsClosure _ bi fv u [] (StgSCC _ cc (StgConApp con args lvs)))
+ = collectCC cc `thenMM_`
+ returnMM (StgRhsCon cc con args)
+-}
+
+ do_rhs (StgRhsClosure _ bi fv u args body@(StgSCC _ cc _))
+ = set_prevailing_cc cc (
+ do_expr body
+ ) `thenMM` \ body' ->
+ returnMM (StgRhsClosure cc bi fv u args body')
+
+ do_rhs (StgRhsClosure cc bi fv u args body)
+ = use_prevailing_cc_maybe cc `thenMM` \ cc2 ->
+ set_prevailing_cc cc2 (
+ do_expr body
+ ) `thenMM` \ body' ->
+ returnMM (StgRhsClosure cc2 bi fv u args body')
+
+ do_rhs (StgRhsCon cc con args)
+ = use_prevailing_cc_maybe cc `thenMM` \ cc2 ->
+ returnMM (StgRhsCon cc2 con args)
+ -- ToDo: Box args (if lex) Pass back let binding???
+ -- Nope: maybe later? WDP 94/06
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Boxing higher-order args}
+%* *
+%************************************************************************
+
+\begin{code}
+boxHigherOrderArgs
+ :: ([PlainStgAtom] -> PlainStgLiveVars -> PlainStgExpr)
+ -- An application lacking its arguments and live-var info
+ -> [PlainStgAtom] -- arguments which we might box
+ -> PlainStgLiveVars -- live var info, which we do *not* try
+ -- to maintain/update (setStgVarInfo will
+ -- do that)
+ -> MassageM PlainStgExpr
+
+boxHigherOrderArgs almost_expr args live_vars
+ = mapAccumMM do_arg [] args `thenMM` \ (let_bindings, new_args) ->
+ get_prevailing_cc `thenMM` \ cc ->
+ returnMM (foldr (mk_stg_let cc) (almost_expr new_args live_vars) let_bindings)
+ where
+ ---------------
+ do_arg bindings atom@(StgLitAtom _) = returnMM (bindings, atom)
+
+ do_arg bindings atom@(StgVarAtom old_var)
+ = let
+ var_type = getIdUniType old_var
+ in
+ if not (is_fun_type var_type) then
+ returnMM (bindings, atom) -- easy
+ else
+ -- make a trivial let-binding for the higher-order guy
+ getUniqueMM `thenMM` \ uniq ->
+ let
+ new_var = mkSysLocal SLIT("ho") uniq var_type mkUnknownSrcLoc
+ in
+ returnMM ( (new_var, old_var) : bindings, StgVarAtom new_var )
+ where
+ is_fun_type ty = isFunType (getTauType ty)
+
+ ---------------
+ mk_stg_let :: CostCentre -> (Id, Id) -> PlainStgExpr -> PlainStgExpr
+
+ mk_stg_let cc (new_var, old_var) body
+ = let
+ rhs_body = StgApp (StgVarAtom old_var) [{-no args-}] bOGUS_LVs
+
+ rhs = StgRhsClosure cc
+ stgArgOcc -- safe...
+ [{-junk-}] Updatable [{-no args-}] rhs_body
+ in
+ StgLet (StgNonRec new_var rhs) body
+ where
+ bOGUS_LVs = emptyUniqSet -- easier to print than: panic "mk_stg_let: LVs"
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Boring monad stuff for this}
+%* *
+%************************************************************************
+
+\begin{code}
+type MassageM result
+ = FAST_STRING -- module name
+ -> CostCentre -- prevailing CostCentre
+ -- if none, subsumedCosts at top-level
+ -- useCurrentCostCentre at nested levels
+ -> SplitUniqSupply
+ -> CollectedCCs
+ -> (CollectedCCs, result)
+
+-- the initUs function also returns the final UniqueSupply and CollectedCCs
+
+initMM :: FAST_STRING -- module name, which we may consult
+ -> SplitUniqSupply
+ -> MassageM a
+ -> (CollectedCCs, a)
+
+initMM mod_name init_us m = m mod_name subsumedCosts{-top-level-} init_us ([],[])
+
+thenMM :: MassageM a -> (a -> MassageM b) -> MassageM b
+thenMM_ :: MassageM a -> (MassageM b) -> MassageM b
+
+thenMM expr cont mod scope_cc us ccs
+ = case splitUniqSupply us of { (s1, s2) ->
+ case (expr mod scope_cc s1 ccs) of { (ccs2, result) ->
+ cont result mod scope_cc s2 ccs2 }}
+
+thenMM_ expr cont mod scope_cc us ccs
+ = case splitUniqSupply us of { (s1, s2) ->
+ case (expr mod scope_cc s1 ccs) of { (ccs2, _) ->
+ cont mod scope_cc s2 ccs2 }}
+
+returnMM :: a -> MassageM a
+returnMM result mod scope_cc us ccs = (ccs, result)
+
+nopMM :: MassageM ()
+nopMM mod scope_cc us ccs = (ccs, ())
+
+mapMM :: (a -> MassageM b) -> [a] -> MassageM [b]
+
+mapMM f [] = returnMM []
+mapMM f (m:ms)
+ = f m `thenMM` \ r ->
+ mapMM f ms `thenMM` \ rs ->
+ returnMM (r:rs)
+
+mapAccumMM :: (acc -> x -> MassageM (acc, y)) -> acc -> [x] -> MassageM (acc, [y])
+
+mapAccumMM f b [] = returnMM (b, [])
+mapAccumMM f b (m:ms)
+ = f b m `thenMM` \ (b2, r) ->
+ mapAccumMM f b2 ms `thenMM` \ (b3, rs) ->
+ returnMM (b3, r:rs)
+
+getUniqueMM :: MassageM Unique
+getUniqueMM mod scope_cc us ccs = (ccs, getSUnique us)
+\end{code}
+
+\begin{code}
+set_prevailing_cc, set_prevailing_cc_maybe
+ :: CostCentre -> MassageM a -> MassageM a
+
+set_prevailing_cc cc_to_set_to action mod scope_cc us ccs
+ = action mod cc_to_set_to us ccs
+ -- set unconditionally
+
+set_prevailing_cc_maybe cc_to_set_to action mod scope_cc us ccs
+ = let
+ -- used when switching from top-level to nested
+ -- scope; if we were chugging along as "subsumed",
+ -- we change to the new thing; otherwise we
+ -- keep what we had.
+
+ cc_to_use
+ = if (costsAreSubsumed scope_cc)
+ then cc_to_set_to
+ else scope_cc -- carry on as before
+ in
+ action mod cc_to_use us ccs
+
+get_prevailing_cc :: MassageM CostCentre
+get_prevailing_cc mod scope_cc us ccs = (ccs, scope_cc)
+
+use_prevailing_cc_maybe :: CostCentre -> MassageM CostCentre
+
+use_prevailing_cc_maybe cc_to_try mod scope_cc us ccs
+ = let
+ cc_to_use
+ = if not (noCostCentreAttached cc_to_try
+ || currentOrSubsumedCosts cc_to_try) then
+ cc_to_try
+ else
+ uncalved_scope_cc
+ -- carry on as before, but be sure it
+ -- isn't marked as CAFish (we're
+ -- crossing a lambda...)
+ in
+ (ccs, cc_to_use)
+ where
+ uncalved_scope_cc = unCafifyCC scope_cc
+\end{code}
+
+\begin{code}
+collectCC :: CostCentre -> MassageM ()
+
+collectCC cc mod_name scope_cc us (local_ccs, extern_ccs)
+ = ASSERT(not (noCostCentreAttached cc))
+ ASSERT(not (currentOrSubsumedCosts cc))
+ if (cc `ccFromThisModule` mod_name) then
+ ((cc : local_ccs, extern_ccs), ())
+ else -- must declare it "extern"
+ ((local_ccs, cc : extern_ccs), ())
+\end{code}