2 % (c) The AQUA Project, Glasgow University, 1993-1995
4 \section[SimplPgm]{Interface to the ``new'' simplifier}
7 #include "HsVersions.h"
9 module SimplPgm ( simplifyPgm ) where
14 import Pretty -- ToDo: rm debugging
17 import AbsUniType ( getTyVarMaybe )
18 import CmdLineOpts ( switchIsOn, intSwitchSet,
19 GlobalSwitch(..), SimplifierSwitch(..)
21 import Id ( cmpId, externallyVisibleId )
24 import Maybes ( catMaybes, Maybe(..) )
28 import Simplify ( simplTopBinds )
29 import OccurAnal -- occurAnalyseBinds
30 #if ! OMIT_FOLDR_BUILD
31 import NewOccurAnal -- newOccurAnalyseBinds
33 import TyVarEnv -- ( nullTyVarEnv )
40 simplifyPgm :: [PlainCoreBinding] -- input
41 -> (GlobalSwitch->SwitchResult) -- switch lookup fns (global
42 -> (SimplifierSwitch->SwitchResult) -- and this-simplification-specific)
43 -> SimplCount -- info about how many times
44 -- each transformation has occurred
46 -> ([PlainCoreBinding], -- output
47 Int, -- info about how much happened
48 SimplCount) -- accumulated simpl stats
50 simplifyPgm binds g_sw_chkr s_sw_chkr simpl_stats us
51 = case (splitUniqSupply us) of { (s1, s2) ->
52 case (initSmpl s1 (simpl_pgm 0 1 binds)) of { ((pgm2, it_count, simpl_stats2), _) ->
53 case (tidy_top pgm2 s2) of { pgm3 ->
54 (pgm3, it_count, combineSimplCounts simpl_stats simpl_stats2) }}}
56 global_switch_is_on = switchIsOn g_sw_chkr
57 simpl_switch_is_on = switchIsOn s_sw_chkr
60 occur_anal = occurAnalyseBinds
62 occur_anal = if simpl_switch_is_on SimplDoNewOccurAnal
63 then newOccurAnalyseBinds
64 else occurAnalyseBinds
68 = case (intSwitchSet s_sw_chkr MaxSimplifierIterations) of
69 Nothing -> 1 -- default
72 simpl_pgm :: Int -> Int -> [PlainCoreBinding] -> SmplM ([PlainCoreBinding], Int, SimplCount)
74 simpl_pgm n iterations pgm
75 = -- find out what top-level binders are used,
76 -- and prepare to unfold all the "simple" bindings
77 -- pprTrace ("\niteration "++show iterations++":\n") (ppr PprDebug pgm) (
79 tagged_pgm = BSCC("OccurBinds")
80 occur_anal pgm global_switch_is_on simpl_switch_is_on
84 simplTopBinds (nullSimplEnv s_sw_chkr) tagged_pgm `thenSmpl` \ new_pgm ->
86 -- Quit if we didn't actually do anything; otherwise,
87 -- try again (if suitable flags)
89 simplCount `thenSmpl` \ r ->
90 detailedSimplCount `thenSmpl` \ dr ->
92 show_status = pprTrace "NewSimpl: " (ppAboves [
93 ppBesides [ppInt iterations, ppChar '/', ppInt max_simpl_iterations],
94 ppStr (showSimplCount dr)
95 --DEBUG: , ppAboves (map (pprPlainCoreBinding PprDebug) new_pgm)
99 (if global_switch_is_on D_verbose_core2core
100 || simpl_switch_is_on ShowSimplifierProgress
104 (let stop_now = r == n {-nothing happened-}
105 || (if iterations > max_simpl_iterations then
106 (if max_simpl_iterations > 1 {-otherwise too boring-} then
108 ("NOTE: Simplifier still going after "++show max_simpl_iterations++" iterations; bailing out.")
115 (if global_switch_is_on D_verbose_core2core
118 (returnSmpl (new_pgm, iterations, dr))
120 simpl_pgm r (iterations + 1) new_pgm
125 In @tidy_top@, we look for things at the top-level of the form...
129 x_exported = x_local -- or perhaps...
131 x_exported = /\ tyvars -> x_local tyvars -- where this is eta-reducible
133 In cases we find like this, we go {\em backwards} and replace
134 \tr{x_local} with \tr{x_exported}. This save a gratuitous jump
135 (from \tr{x_exported} to \tr{x_local}), and makes strictness
136 information propagate better.
138 If more than one exported thing is equal to a local thing (i.e., the
139 local thing really is shared), then obviously we give up.
141 Strategy: first collect the info; then make a \tr{Id -> Id} mapping.
142 Then blast the whole program (LHSs as well as RHSs) with it.
145 type BlastEnv = IdEnv Id -- domain is local Ids; range is exported Ids
147 not_elem = isn'tIn "undup"
149 tidy_top :: [PlainCoreBinding] -> SUniqSM [PlainCoreBinding]
152 = if null blast_alist then
153 returnSUs binds_in -- no joy there
155 -- pprTrace "undup output length:" (ppInt (length blast_alist)) (
156 mapSUs blast binds_in `thenSUs` \ binds_maybe ->
157 returnSUs (catMaybes binds_maybe)
160 blast_alist = undup (foldl find_cand [] binds_in)
161 blast_id_env = mkIdEnv blast_alist
162 blast_val_env= mkIdEnv [ (l, CoVar e) | (l,e) <- blast_alist ]
163 blast_all_exps = map snd blast_alist
166 find_cand blast_list (CoRec _) = blast_list -- recursively paranoid, as usual
168 find_cand blast_list (CoNonRec binder rhs)
169 = if not (isExported binder) then
172 case rhs_equiv_to_local_var rhs of
173 Nothing -> blast_list
174 Just local -> (local, binder) : blast_list -- tag it on
176 ------------------------------------------
177 -- if an Id appears >1 time in the domain,
178 -- *all* occurrences must be expunged.
179 undup :: [(Id, Id)] -> [(Id, Id)]
182 = -- pprTrace "undup input length:" (ppInt (length blast_list)) (
184 (singles, dups) = removeDups cmp blast_list
185 list_of_dups = concat dups
187 [ s | s <- singles, s `not_elem` list_of_dups ]
190 cmp (x,_) (y,_) = x `cmpId` y
192 ------------------------------------------
193 rhs_equiv_to_local_var (CoVar x)
194 = if externallyVisibleId x then Nothing else Just x
196 rhs_equiv_to_local_var expr = Nothing
198 = case (digForLambdas expr) of { (tyvars, binders, body) ->
199 case (collectArgs body) of { (fun, args) ->
201 CoVar x -> if null binders
202 && not (isExported x)
203 && tylams_match_tyargs tyvars args then
204 -- may need to chk for "tyvars" occurring in "x"'s type
211 -- looking for a very restricted special case:
212 -- /\ tv1 tv2 ... -> var tv1 tv2 ...
214 tylams_match_tyargs [] [] = True
215 tylams_match_tyargs (tv:tvs) (TypeArg ty : args)
216 = ASSERT(not (isPrimType ty))
217 case (getTyVarMaybe ty) of
219 Just tyvar -> tv == tyvar
220 tylams_match_tyargs _ _ = False
223 ------------------------------------------
224 -- "blast" does the substitution:
225 -- returns Nothing if a binding goes away
226 -- returns "Just b" to give back a fixed-up binding
228 blast :: PlainCoreBinding -> SUniqSM (Maybe PlainCoreBinding)
231 = mapSUs blast_pr pairs `thenSUs` \ blasted_pairs ->
232 returnSUs (Just (CoRec blasted_pairs))
234 blast_pr (binder, rhs)
235 = subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenSUs` \ blasted_rhs ->
237 case lookupIdEnv blast_id_env binder of
238 Just exportee -> (exportee, blasted_rhs)
239 Nothing -> (binder, blasted_rhs)
242 blast (CoNonRec binder rhs)
243 = if binder `is_elem` blast_all_exps then
244 returnSUs Nothing -- this binding dies!
246 subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenSUs` \ blasted_rhs ->
248 case lookupIdEnv blast_id_env binder of
249 Just exportee -> CoNonRec exportee blasted_rhs
250 Nothing -> CoNonRec binder blasted_rhs
253 is_elem = isIn "blast"
255 subst_CoreExprUS e1 e2 rhs us = snd (substCoreExprUS e1 e2 rhs (mkUniqueSupplyGrimily us))