2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[SimplCore]{Driver for simplifying @Core@ programs}
7 module SimplCore ( core2core ) where
9 #include "HsVersions.h"
11 import CmdLineOpts ( CoreToDo(..), SimplifierSwitch(..),
12 SwitchResult(..), switchIsOn, intSwitchSet,
13 opt_D_dump_occur_anal, opt_D_dump_rules,
14 opt_D_dump_simpl_iterations,
15 opt_D_dump_simpl_stats,
16 opt_D_dump_simpl, opt_D_dump_rules,
17 opt_D_verbose_core2core,
18 opt_D_dump_occur_anal,
21 import CoreLint ( beginPass, endPass )
23 import CSE ( cseProgram )
24 import Rules ( RuleBase, ProtoCoreRule(..), pprProtoCoreRule, prepareLocalRuleBase,
25 prepareOrphanRuleBase, unionRuleBase, localRule, orphanRule )
27 import PprCore ( pprCoreBindings )
28 import OccurAnal ( occurAnalyseBinds )
29 import CoreUtils ( exprIsTrivial, etaReduceExpr )
30 import Simplify ( simplTopBinds, simplExpr )
31 import SimplUtils ( findDefault, simplBinders )
33 import Literal ( Literal(..), literalType, mkMachInt )
34 import ErrUtils ( dumpIfSet )
35 import FloatIn ( floatInwards )
36 import FloatOut ( floatOutwards )
37 import Id ( Id, mkSysLocal, mkVanillaId, isBottomingId, isDataConWrapId,
38 idType, setIdType, idName, idInfo, setIdNoDiscard
42 import Module ( Module )
43 import Name ( mkLocalName, tidyOccName, tidyTopName,
44 NamedThing(..), OccName
46 import TyCon ( TyCon, isDataTyCon )
47 import PrelRules ( builtinRules )
50 tidyType, tidyTypes, tidyTopType, tidyTyVar, tidyTyVars,
53 import TysWiredIn ( smallIntegerDataCon, isIntegerTy )
54 import LiberateCase ( liberateCase )
55 import SAT ( doStaticArgs )
56 import Specialise ( specProgram)
57 import UsageSPInf ( doUsageSPInf )
58 import StrictAnal ( saBinds )
59 import WorkWrap ( wwTopBinds )
60 import CprAnalyse ( cprAnalyse )
62 import Unique ( Unique, Uniquable(..) )
63 import UniqSupply ( UniqSupply, mkSplitUniqSupply, splitUniqSupply, uniqFromSupply )
64 import Util ( mapAccumL )
65 import SrcLoc ( noSrcLoc )
68 import IO ( hPutStr, stderr )
71 import Ratio ( numerator, denominator )
72 import List ( partition )
75 %************************************************************************
77 \subsection{The driver for the simplifier}
79 %************************************************************************
82 core2core :: [CoreToDo] -- Spec of what core-to-core passes to do
83 -> [CoreBind] -- Binds in
84 -> [ProtoCoreRule] -- Rules in
85 -> IO ([CoreBind], RuleBase) -- binds, local orphan rules out
87 core2core core_todos binds rules
89 us <- mkSplitUniqSupply 's'
90 let (cp_us, us1) = splitUniqSupply us
91 (ru_us, ps_us) = splitUniqSupply us1
93 let (local_rules, imported_rules) = partition localRule rules
95 better_local_rules <- simplRules ru_us local_rules binds
97 let all_imported_rules = builtinRules ++ imported_rules
98 -- Here is where we add in the built-in rules
100 let (binds1, local_rule_base) = prepareLocalRuleBase binds better_local_rules
101 imported_rule_base = prepareOrphanRuleBase all_imported_rules
103 -- Do the main business
104 (stats, processed_binds, processed_local_rules)
105 <- doCorePasses zeroSimplCount cp_us binds1 local_rule_base
106 imported_rule_base Nothing core_todos
108 dumpIfSet opt_D_dump_simpl_stats
109 "Grand total simplifier statistics"
110 (pprSimplCount stats)
113 -- We only return local orphan rules, i.e., local rules not attached to an Id
114 return (processed_binds, processed_local_rules)
117 doCorePasses :: SimplCount -- simplifier stats
118 -> UniqSupply -- uniques
119 -> [CoreBind] -- local binds in (with rules attached)
120 -> RuleBase -- local orphan rules
121 -> RuleBase -- imported and builtin rules
122 -> Maybe RuleBase -- combined rulebase, or Nothing to ask for it to be rebuilt
123 -> [CoreToDo] -- which passes to do
124 -> IO (SimplCount, [CoreBind], RuleBase) -- stats, binds, local orphan rules
126 doCorePasses stats us binds lrb irb rb0 []
127 = return (stats, binds, lrb)
129 doCorePasses stats us binds lrb irb rb0 (to_do : to_dos)
131 let (us1, us2) = splitUniqSupply us
133 -- recompute rulebase if necessary
134 let rb = maybe (irb `unionRuleBase` lrb) id rb0
136 (stats1, binds1, mlrb1) <- doCorePass us1 binds lrb rb to_do
138 -- request rulebase recomputation if pass returned a new local rulebase
139 let (lrb1,rb1) = maybe (lrb, Just rb) (\ lrb1 -> (lrb1, Nothing)) mlrb1
141 doCorePasses (stats `plusSimplCount` stats1) us2 binds1 lrb1 irb rb1 to_dos
143 doCorePass us binds lrb rb (CoreDoSimplify sw_chkr) = _scc_ "Simplify" simplifyPgm rb sw_chkr us binds
144 doCorePass us binds lrb rb CoreCSE = _scc_ "CommonSubExpr" noStats (cseProgram binds)
145 doCorePass us binds lrb rb CoreLiberateCase = _scc_ "LiberateCase" noStats (liberateCase binds)
146 doCorePass us binds lrb rb CoreDoFloatInwards = _scc_ "FloatInwards" noStats (floatInwards binds)
147 doCorePass us binds lrb rb (CoreDoFloatOutwards f) = _scc_ "FloatOutwards" noStats (floatOutwards f us binds)
148 doCorePass us binds lrb rb CoreDoStaticArgs = _scc_ "StaticArgs" noStats (doStaticArgs us binds)
149 doCorePass us binds lrb rb CoreDoStrictness = _scc_ "Stranal" noStats (saBinds binds)
150 doCorePass us binds lrb rb CoreDoWorkerWrapper = _scc_ "WorkWrap" noStats (wwTopBinds us binds)
151 doCorePass us binds lrb rb CoreDoSpecialising = _scc_ "Specialise" noStats (specProgram us binds)
152 doCorePass us binds lrb rb CoreDoCPResult = _scc_ "CPResult" noStats (cprAnalyse binds)
153 doCorePass us binds lrb rb CoreDoPrintCore = _scc_ "PrintCore" noStats (printCore binds)
154 doCorePass us binds lrb rb CoreDoUSPInf
155 = _scc_ "CoreUsageSPInf"
156 if opt_UsageSPOn then
158 (binds1, rules1) <- doUsageSPInf us binds lrb
159 return (zeroSimplCount, binds1, rules1)
161 trace "WARNING: ignoring requested -fusagesp pass; requires -fusagesp-on" $
162 return (zeroSimplCount, binds, Nothing)
164 printCore binds = do dumpIfSet True "Print Core"
165 (pprCoreBindings binds)
168 -- most passes return no stats and don't change rules
169 noStats thing = do { binds <- thing; return (zeroSimplCount, binds, Nothing) }
173 %************************************************************************
175 \subsection{Dealing with rules}
177 %************************************************************************
179 We must do some gentle simplifiation on the template (but not the RHS)
180 of each rule. The case that forced me to add this was the fold/build rule,
181 which without simplification looked like:
182 fold k z (build (/\a. g a)) ==> ...
183 This doesn't match unless you do eta reduction on the build argument.
186 simplRules :: UniqSupply -> [ProtoCoreRule] -> [CoreBind] -> IO [ProtoCoreRule]
187 simplRules us rules binds
188 = do let (better_rules,_) = initSmpl sw_chkr us bind_vars black_list_all (mapSmpl simplRule rules)
190 dumpIfSet opt_D_dump_rules
191 "Transformation rules"
192 (vcat (map pprProtoCoreRule better_rules))
196 black_list_all v = not (isDataConWrapId v)
197 -- This stops all inlining except the
198 -- wrappers for data constructors
200 sw_chkr any = SwBool False -- A bit bogus
202 -- Boringly, we need to gather the in-scope set.
203 -- Typically this thunk won't even be force, but the test in
204 -- simpVar fails if it isn't right, and it might conceivably matter
205 bind_vars = foldr (unionVarSet . mkVarSet . bindersOf) emptyVarSet binds
208 simplRule rule@(ProtoCoreRule is_local id (Rule name bndrs args rhs))
210 = returnSmpl rule -- No need to fiddle with imported rules
212 = simplBinders bndrs $ \ bndrs' ->
213 mapSmpl simpl_arg args `thenSmpl` \ args' ->
214 simplExpr rhs `thenSmpl` \ rhs' ->
215 returnSmpl (ProtoCoreRule is_local id (Rule name bndrs' args' rhs'))
218 -- I've seen rules in which a LHS like
219 -- augment g (build h)
221 -- augment (\a. g a) (build h)
222 -- So it's a help to eta-reduce the args as we simplify them.
223 -- Otherwise we don't match when given an argument like
225 = simplExpr e `thenSmpl` \ e' ->
226 returnSmpl (etaReduceExpr e')
229 %************************************************************************
231 \subsection{The driver for the simplifier}
233 %************************************************************************
236 simplifyPgm :: RuleBase
237 -> (SimplifierSwitch -> SwitchResult)
239 -> [CoreBind] -- Input
240 -> IO (SimplCount, [CoreBind], Maybe RuleBase) -- New bindings
242 simplifyPgm (imported_rule_ids, rule_lhs_fvs)
245 beginPass "Simplify";
247 -- Glom all binds together in one Rec, in case any
248 -- transformations have introduced any new dependencies
250 -- NB: the global invariant is this:
251 -- *** the top level bindings are never cloned, and are always unique ***
253 -- We sort them into dependency order, but applying transformation rules may
254 -- make something at the top refer to something at the bottom:
258 -- RULE: p (q x) = h x
260 -- Applying this rule makes f refer to h, although it doesn't appear to in the
261 -- source program. Our solution is to do this occasional glom-together step,
262 -- just once per overall simplfication step.
264 let { recd_binds = [Rec (flattenBinds binds)] };
266 (termination_msg, it_count, counts_out, binds') <- iteration us 1 zeroSimplCount recd_binds;
268 dumpIfSet (opt_D_verbose_core2core && opt_D_dump_simpl_stats)
269 "Simplifier statistics"
270 (vcat [text termination_msg <+> text "after" <+> ppr it_count <+> text "iterations",
272 pprSimplCount counts_out]);
275 (opt_D_verbose_core2core && not opt_D_dump_simpl_iterations)
278 return (counts_out, binds', Nothing)
281 max_iterations = getSimplIntSwitch sw_chkr MaxSimplifierIterations
282 black_list_fn = blackListed rule_lhs_fvs (intSwitchSet sw_chkr SimplInlinePhase)
284 core_iter_dump binds | opt_D_verbose_core2core = pprCoreBindings binds
287 iteration us iteration_no counts binds
289 -- Occurrence analysis
290 let { tagged_binds = _scc_ "OccAnal" occurAnalyseBinds binds } ;
292 dumpIfSet opt_D_dump_occur_anal "Occurrence analysis"
293 (pprCoreBindings tagged_binds);
296 -- We do this with a *case* not a *let* because lazy pattern
297 -- matching bit us with bad space leak!
298 -- With a let, we ended up with
303 -- case t of {(_,counts') -> if counts'=0 then ...
304 -- So the conditional didn't force counts', because the
305 -- selection got duplicated. Sigh!
306 case initSmpl sw_chkr us1 imported_rule_ids black_list_fn
307 (simplTopBinds tagged_binds)
308 of { (binds', counts') -> do {
309 -- The imported_rule_ids are used by initSmpl to initialise
310 -- the in-scope set. That way, the simplifier will change any
311 -- occurrences of the imported id to the one in the imported_rule_ids
312 -- set, which are decorated with their rules.
314 let { all_counts = counts `plusSimplCount` counts' } ;
316 -- Stop if nothing happened; don't dump output
317 if isZeroSimplCount counts' then
318 return ("Simplifier reached fixed point", iteration_no, all_counts, binds')
321 -- Dump the result of this iteration
322 dumpIfSet opt_D_dump_simpl_iterations
323 ("Simplifier iteration " ++ show iteration_no
324 ++ " out of " ++ show max_iterations)
325 (pprSimplCount counts') ;
327 if opt_D_dump_simpl_iterations then
328 endPass ("Simplifier iteration " ++ show iteration_no ++ " result")
329 opt_D_verbose_core2core
334 -- Stop if we've run out of iterations
335 if iteration_no == max_iterations then
338 if max_iterations > 2 then
339 hPutStr stderr ("NOTE: Simplifier still going after " ++
340 show max_iterations ++
341 " iterations; bailing out.\n")
346 return ("Simplifier baled out", iteration_no, all_counts, binds')
350 else iteration us2 (iteration_no + 1) all_counts binds'
353 (us1, us2) = splitUniqSupply us