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
11 import Type ( getTyVarMaybe )
12 import CmdLineOpts ( switchIsOn, intSwitchSet,
13 GlobalSwitch(..), SimplifierSwitch(..)
15 import Id ( externallyVisibleId )
17 import Maybes ( catMaybes, Maybe(..) )
21 import Simplify ( simplTopBinds )
22 import OccurAnal -- occurAnalyseBinds
28 simplifyPgm :: [CoreBinding] -- input
29 -> (GlobalSwitch->SwitchResult) -- switch lookup fns (global
30 -> (SimplifierSwitch->SwitchResult) -- and this-simplification-specific)
31 -> SimplCount -- info about how many times
32 -- each transformation has occurred
34 -> ([CoreBinding], -- output
35 Int, -- info about how much happened
36 SimplCount) -- accumulated simpl stats
38 simplifyPgm binds g_sw_chkr s_sw_chkr simpl_stats us
39 = case (splitUniqSupply us) of { (s1, s2) ->
40 case (initSmpl s1 (simpl_pgm 0 1 binds)) of { ((pgm2, it_count, simpl_stats2), _) ->
41 case (tidy_top pgm2 s2) of { pgm3 ->
42 (pgm3, it_count, combineSimplCounts simpl_stats simpl_stats2) }}}
44 global_switch_is_on = switchIsOn g_sw_chkr
45 simpl_switch_is_on = switchIsOn s_sw_chkr
47 occur_anal = occurAnalyseBinds
50 = case (intSwitchSet s_sw_chkr MaxSimplifierIterations) of
51 Nothing -> 1 -- default
54 simpl_pgm :: Int -> Int -> [CoreBinding] -> SmplM ([CoreBinding], Int, SimplCount)
56 simpl_pgm n iterations pgm
57 = -- find out what top-level binders are used,
58 -- and prepare to unfold all the "simple" bindings
59 -- pprTrace ("\niteration "++show iterations++":\n") (ppr PprDebug pgm) (
61 tagged_pgm = BSCC("OccurBinds")
62 occur_anal pgm global_switch_is_on simpl_switch_is_on
66 simplTopBinds (nullSimplEnv s_sw_chkr) tagged_pgm `thenSmpl` \ new_pgm ->
68 -- Quit if we didn't actually do anything; otherwise,
69 -- try again (if suitable flags)
71 simplCount `thenSmpl` \ r ->
72 detailedSimplCount `thenSmpl` \ dr ->
74 show_status = pprTrace "NewSimpl: " (ppAboves [
75 ppBesides [ppInt iterations, ppChar '/', ppInt max_simpl_iterations],
76 ppStr (showSimplCount dr)
77 --DEBUG: , ppAboves (map (pprPlainCoreBinding PprDebug) new_pgm)
81 (if global_switch_is_on D_verbose_core2core
82 || simpl_switch_is_on ShowSimplifierProgress
86 (let stop_now = r == n {-nothing happened-}
87 || (if iterations > max_simpl_iterations then
88 (if max_simpl_iterations > 1 {-otherwise too boring-} then
90 ("NOTE: Simplifier still going after "++show max_simpl_iterations++" iterations; bailing out.")
97 returnSmpl (new_pgm, iterations, dr)
99 simpl_pgm r (iterations + 1) new_pgm
104 In @tidy_top@, we look for things at the top-level of the form...
108 x_exported = x_local -- or perhaps...
110 x_exported = /\ tyvars -> x_local tyvars -- where this is eta-reducible
112 In cases we find like this, we go {\em backwards} and replace
113 \tr{x_local} with \tr{x_exported}. This save a gratuitous jump
114 (from \tr{x_exported} to \tr{x_local}), and makes strictness
115 information propagate better.
117 If more than one exported thing is equal to a local thing (i.e., the
118 local thing really is shared), then obviously we give up.
120 Strategy: first collect the info; then make a \tr{Id -> Id} mapping.
121 Then blast the whole program (LHSs as well as RHSs) with it.
124 type BlastEnv = IdEnv Id -- domain is local Ids; range is exported Ids
126 not_elem = isn'tIn "undup"
128 tidy_top :: [CoreBinding] -> UniqSM [CoreBinding]
131 = if null blast_alist then
132 returnUs binds_in -- no joy there
134 -- pprTrace "undup output length:" (ppInt (length blast_alist)) (
135 mapUs blast binds_in `thenUs` \ binds_maybe ->
136 returnUs (catMaybes binds_maybe)
139 blast_alist = undup (foldl find_cand [] binds_in)
140 blast_id_env = mkIdEnv blast_alist
141 blast_val_env= mkIdEnv [ (l, Var e) | (l,e) <- blast_alist ]
142 blast_all_exps = map snd blast_alist
145 find_cand blast_list (Rec _) = blast_list -- recursively paranoid, as usual
147 find_cand blast_list (NonRec binder rhs)
148 = if not (isExported binder) then
151 case rhs_equiv_to_local_var rhs of
152 Nothing -> blast_list
153 Just local -> (local, binder) : blast_list -- tag it on
155 ------------------------------------------
156 -- if an Id appears >1 time in the domain,
157 -- *all* occurrences must be expunged.
158 undup :: [(Id, Id)] -> [(Id, Id)]
161 = -- pprTrace "undup input length:" (ppInt (length blast_list)) (
163 (singles, dups) = removeDups compare blast_list
164 list_of_dups = concat dups
166 [ s | s <- singles, s `not_elem` list_of_dups ]
169 compare (x,_) (y,_) = x `cmp` y
171 ------------------------------------------
172 rhs_equiv_to_local_var (Var x)
173 = if externallyVisibleId x then Nothing else Just x
175 rhs_equiv_to_local_var expr = Nothing
177 ------------------------------------------
178 -- "blast" does the substitution:
179 -- returns Nothing if a binding goes away
180 -- returns "Just b" to give back a fixed-up binding
182 blast :: CoreBinding -> UniqSM (Maybe CoreBinding)
185 = mapUs blast_pr pairs `thenUs` \ blasted_pairs ->
186 returnUs (Just (Rec blasted_pairs))
188 blast_pr (binder, rhs)
189 = subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenUs` \ blasted_rhs ->
191 case lookupIdEnv blast_id_env binder of
192 Just exportee -> (exportee, blasted_rhs)
193 Nothing -> (binder, blasted_rhs)
196 blast (NonRec binder rhs)
197 = if binder `is_elem` blast_all_exps then
198 returnUs Nothing -- this binding dies!
200 subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenUs` \ blasted_rhs ->
202 case lookupIdEnv blast_id_env binder of
203 Just exportee -> NonRec exportee blasted_rhs
204 Nothing -> NonRec binder blasted_rhs
207 is_elem = isIn "blast"
209 subst_CoreExprUS e1 e2 rhs us = snd (substCoreExprUS e1 e2 rhs (mkUniqueSupplyGrimily us))