2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
4 \section[SimplStg]{Driver for simplifying @STG@ programs}
7 #include "HsVersions.h"
9 module SimplStg ( stg2stg ) where
16 import LambdaLift ( liftProgram )
17 import SCCfinal ( stgMassageForProfiling )
18 import SatStgRhs ( satStgRhs )
19 import StgStats ( showStgStats )
20 import StgVarInfo ( setStgVarInfo )
21 import UpdAnal ( updateAnalyse )
24 import Id ( unlocaliseId )
26 import Maybes ( maybeToBool, Maybe(..) )
29 import StgLint ( lintStgBindings )
30 import StgSAT ( doStaticArgs )
37 stg2stg :: [StgToDo] -- spec of what stg-to-stg passes to do
38 -> (GlobalSwitch -> SwitchResult)-- access to all global cmd-line opts
39 -> FAST_STRING -- module name (profiling only)
40 -> PprStyle -- printing style (for debugging only)
41 -> UniqSupply -- a name supply
42 -> [StgBinding] -- input...
44 ([StgBinding], -- output program...
45 ([CostCentre], -- local cost-centres that need to be decl'd
46 [CostCentre])) -- "extern" cost-centres
48 stg2stg stg_todos sw_chkr module_name ppr_style us binds
50 case (splitUniqSupply us) of { (us4now, us4later) ->
52 (if do_verbose_stg2stg then
53 writeMn stderr "VERBOSE STG-TO-STG:\n" `thenMn_`
54 writeMn stderr (ppShow 1000
55 (ppAbove (ppStr ("*** Core2Stg:"))
56 (ppAboves (map (ppr ppr_style) (setStgVarInfo False binds)))
58 else returnMn ()) `thenMn_`
60 -- Do the main business!
61 foldl_mn do_stg_pass (binds, us4now, ([],[])) stg_todos
62 `thenMn` \ (processed_binds, _, cost_centres) ->
63 -- Do essential wind-up: part (a) is SatStgRhs
65 -- Not optional, because correct arity information is used by
66 -- the code generator. Afterwards do setStgVarInfo; it gives
67 -- the wrong answers if arities are subsequently changed,
68 -- which stgSatRhs might do. Furthermore, setStgVarInfo
69 -- decides about let-no-escape things, which in turn do a
70 -- better job if arities are correct, which is done by
73 case (satStgRhs processed_binds us4later) of { saturated_binds ->
75 -- Essential wind-up: part (b), eliminate indirections
77 let no_ind_binds = elimIndirections saturated_binds in
80 -- Essential wind-up: part (c), do setStgVarInfo. It has to
81 -- happen regardless, because the code generator uses its
84 -- Why does it have to happen last? Because earlier passes
85 -- may move things around, which would change the live-var
86 -- info. Also, setStgVarInfo decides about let-no-escape
87 -- things, which in turn do a better job if arities are
88 -- correct, which is done by satStgRhs.
91 -- ToDo: provide proper flag control!
93 = if not do_unlocalising
95 else snd (unlocaliseStgBinds unlocal_tag nullIdEnv no_ind_binds)
97 returnMn (setStgVarInfo do_let_no_escapes binds_to_mangle, cost_centres)
101 switch_is_on = switchIsOn sw_chkr
103 do_let_no_escapes = switch_is_on StgDoLetNoEscapes
104 do_verbose_stg2stg = switch_is_on D_verbose_stg2stg
106 (do_unlocalising, unlocal_tag)
107 = case (stringSwitchSet sw_chkr EnsureSplittableC) of
108 Nothing -> (False, panic "tag")
109 Just tag -> (True, _PK_ tag)
111 grp_name = case (stringSwitchSet sw_chkr SccGroup) of
113 Nothing -> module_name -- default: module name
116 stg_linter = if False -- LATER: switch_is_on DoCoreLinting -- ToDo: DoStgLinting flag
117 then lintStgBindings ppr_style
118 else ( \ whodunnit binds -> binds )
120 -------------------------------------------
121 do_stg_pass (binds, us, ccs) to_do
123 (us1, us2) = splitUniqSupply us
127 ASSERT(null (fst ccs) && null (snd ccs))
128 BSCC("StgStaticArgs")
130 binds3 = doStaticArgs binds us1
132 end_pass us2 "StgStaticArgs" ccs binds3
135 StgDoUpdateAnalysis ->
136 ASSERT(null (fst ccs) && null (snd ccs))
138 -- NB We have to do setStgVarInfo first! (There's one
139 -- place free-var info is used) But no let-no-escapes,
140 -- because update analysis doesn't care.
141 end_pass us2 "UpdAnal" ccs (updateAnalyse (setStgVarInfo False binds))
145 trace (showStgStats binds)
146 end_pass us2 "StgStats" ccs binds
149 BSCC("StgLambdaLift")
150 -- NB We have to do setStgVarInfo first!
152 binds3 = liftProgram us1 (setStgVarInfo do_let_no_escapes binds)
154 end_pass us2 "LambdaLift" ccs binds3
157 StgDoMassageForProfiling ->
160 (collected_CCs, binds3)
161 = stgMassageForProfiling module_name grp_name us1 switch_is_on binds
163 end_pass us2 "ProfMassage" collected_CCs binds3
166 end_pass us2 what ccs binds2
167 = -- report verbosely, if required
168 (if do_verbose_stg2stg then
169 writeMn stderr (ppShow 1000
170 (ppAbove (ppStr ("*** "++what++":"))
171 (ppAboves (map (ppr ppr_style) binds2))
173 else returnMn ()) `thenMn_`
175 linted_binds = stg_linter what binds2
177 returnMn (linted_binds, us2, ccs)
178 -- return: processed binds
179 -- UniqueSupply for the next guy to use
180 -- cost-centres to be declared/registered (specialised)
181 -- add to description of what's happened (reverse order)
183 -- here so it can be inlined...
184 foldl_mn f z [] = returnMn z
185 foldl_mn f z (x:xs) = f z x `thenMn` \ zz ->
189 %************************************************************************
191 \subsection[SimplStg-unlocalise]{Unlocalisation in STG code}
193 %************************************************************************
195 The idea of all this ``unlocalise'' stuff is that in certain (prelude
196 only) modules we split up the .hc file into lots of separate little
197 files, which are separately compiled by the C compiler. That gives
198 lots of little .o files. The idea is that if you happen to mention
199 one of them you don't necessarily pull them all in. (Pulling in a
200 piece you don't need can be v bad, because it may mention other pieces
201 you don't need either, and so on.)
203 Sadly, splitting up .hc files means that local names (like s234) are
204 now globally visible, which can lead to clashes between two .hc
205 files. So unlocaliseWhatnot goes through making all the local things
206 into global things, essentially by giving them full names so when they
207 are printed they'll have their module name too. Pretty revolting
211 type UnlocalEnv = IdEnv Id
213 lookup_uenv :: UnlocalEnv -> Id -> Id
214 lookup_uenv env id = case lookupIdEnv env id of
216 Just new_id -> new_id
218 unlocaliseStgBinds :: FAST_STRING -> UnlocalEnv -> [StgBinding] -> (UnlocalEnv, [StgBinding])
220 unlocaliseStgBinds mod uenv [] = (uenv, [])
222 unlocaliseStgBinds mod uenv (b : bs)
223 = BIND unlocal_top_bind mod uenv b _TO_ (new_uenv, new_b) ->
224 BIND unlocaliseStgBinds mod new_uenv bs _TO_ (uenv3, new_bs) ->
225 (uenv3, new_b : new_bs)
230 unlocal_top_bind :: FAST_STRING -> UnlocalEnv -> StgBinding -> (UnlocalEnv, StgBinding)
232 unlocal_top_bind mod uenv bind@(StgNonRec binder _)
233 = let new_uenv = case unlocaliseId mod binder of
235 Just new_binder -> addOneToIdEnv uenv binder new_binder
237 (new_uenv, renameTopStgBind (lookup_uenv new_uenv) bind)
239 unlocal_top_bind mod uenv bind@(StgRec pairs)
240 = let maybe_unlocaliseds = [ (b, unlocaliseId mod b) | (b, _) <- pairs ]
241 new_uenv = growIdEnvList uenv [ (b,new_b)
242 | (b, Just new_b) <- maybe_unlocaliseds]
244 (new_uenv, renameTopStgBind (lookup_uenv new_uenv) bind)
247 %************************************************************************
249 \subsection[SimplStg-indirections]{Eliminating indirections in STG code}
251 %************************************************************************
253 In @elimIndirections@, we look for things at the top-level of the form...
260 In cases we find like this, we go {\em backwards} and replace
261 \tr{x_local} with \tr{...rhs...}, to produce
263 x_exported = ...rhs...
267 This saves a gratuitous jump
268 (from \tr{x_exported} to \tr{x_local}), and makes strictness
269 information propagate better.
271 If more than one exported thing is equal to a local thing (i.e., the
272 local thing really is shared), then we eliminate only the first one. Thus:
276 x_exported1 = x_local
278 x_exported2 = x_local
283 x_exported1 = ....rhs...
286 x_exported2 = x_exported1
290 We also have to watch out for
294 This can arise post lambda lifting; the original might have been
296 f = \xyz -> letrec g = [xy] \ [k] -> e
300 Strategy: first collect the info; then make a \tr{Id -> Id} mapping.
301 Then blast the whole program (LHSs as well as RHSs) with it.
304 elimIndirections :: [StgBinding] -> [StgBinding]
306 elimIndirections binds_in
307 = if isNullIdEnv blast_env then
308 binds_in -- Nothing to do
310 [renameTopStgBind lookup_fn bind | Just bind <- reduced_binds]
312 lookup_fn id = case lookupIdEnv blast_env id of
313 Just new_id -> new_id
316 (blast_env, reduced_binds) = mapAccumL try_bind nullIdEnv binds_in
318 try_bind :: IdEnv Id -> StgBinding -> (IdEnv Id, Maybe StgBinding)
320 (StgNonRec exported_binder
321 (StgRhsClosure _ _ _ _
323 (StgApp (StgVarArg local_binder) fun_args _)
325 | isExported exported_binder && -- Only if this is exported
326 not (isExported local_binder) && -- Only if this one is defined in this
327 isLocallyDefined local_binder && -- module, so that we *can* change its
328 -- binding to be the exported thing!
329 not (in_dom env_so_far local_binder) && -- Only if we havn't seen it before
330 args_match lambda_args fun_args -- Just an eta-expansion
332 = (addOneToIdEnv env_so_far local_binder exported_binder,
335 args_match [] [] = True
336 args_match (la:las) (StgVarArg fa:fas) = la == fa && args_match las fas
337 args_match _ _ = False
339 try_bind env_so_far bind
340 = (env_so_far, Just bind)
342 in_dom env id = maybeToBool (lookupIdEnv env id)
345 @renameTopStgBind@ renames top level binders and all occurrences thereof.
348 renameTopStgBind :: (Id -> Id) -> StgBinding -> StgBinding
350 renameTopStgBind fn (StgNonRec b rhs) = StgNonRec (fn b) (mapStgBindeesRhs fn rhs)
351 renameTopStgBind fn (StgRec pairs) = StgRec [ (fn b, mapStgBindeesRhs fn r) | (b, r) <- pairs ]