| 1 | % |
|---|
| 2 | % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 |
|---|
| 3 | % |
|---|
| 4 | \section[SimplCore]{Driver for simplifying @Core@ programs} |
|---|
| 5 | |
|---|
| 6 | \begin{code} |
|---|
| 7 | {-# OPTIONS -fno-warn-tabs #-} |
|---|
| 8 | -- The above warning supression flag is a temporary kludge. |
|---|
| 9 | -- While working on this module you are encouraged to remove it and |
|---|
| 10 | -- detab the module (please do the detabbing in a separate patch). See |
|---|
| 11 | -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces |
|---|
| 12 | -- for details |
|---|
| 13 | |
|---|
| 14 | module SimplCore ( core2core, simplifyExpr ) where |
|---|
| 15 | |
|---|
| 16 | #include "HsVersions.h" |
|---|
| 17 | |
|---|
| 18 | import DynFlags |
|---|
| 19 | import CoreSyn |
|---|
| 20 | import CoreSubst |
|---|
| 21 | import HscTypes |
|---|
| 22 | import CSE ( cseProgram ) |
|---|
| 23 | import Rules ( RuleBase, emptyRuleBase, mkRuleBase, unionRuleBase, |
|---|
| 24 | extendRuleBaseList, ruleCheckProgram, addSpecInfo, ) |
|---|
| 25 | import PprCore ( pprCoreBindings, pprCoreExpr ) |
|---|
| 26 | import OccurAnal ( occurAnalysePgm, occurAnalyseExpr ) |
|---|
| 27 | import IdInfo |
|---|
| 28 | import CoreUtils ( coreBindsSize, coreBindsStats, exprSize ) |
|---|
| 29 | import Simplify ( simplTopBinds, simplExpr ) |
|---|
| 30 | import SimplUtils ( simplEnvForGHCi, activeRule ) |
|---|
| 31 | import SimplEnv |
|---|
| 32 | import SimplMonad |
|---|
| 33 | import CoreMonad |
|---|
| 34 | import qualified ErrUtils as Err |
|---|
| 35 | import FloatIn ( floatInwards ) |
|---|
| 36 | import FloatOut ( floatOutwards ) |
|---|
| 37 | import FamInstEnv |
|---|
| 38 | import Id |
|---|
| 39 | import BasicTypes ( CompilerPhase(..), isDefaultInlinePragma ) |
|---|
| 40 | import VarSet |
|---|
| 41 | import VarEnv |
|---|
| 42 | import LiberateCase ( liberateCase ) |
|---|
| 43 | import SAT ( doStaticArgs ) |
|---|
| 44 | import Specialise ( specProgram) |
|---|
| 45 | import SpecConstr ( specConstrProgram) |
|---|
| 46 | import DmdAnal ( dmdAnalPgm ) |
|---|
| 47 | import WorkWrap ( wwTopBinds ) |
|---|
| 48 | import Vectorise ( vectorise ) |
|---|
| 49 | import FastString |
|---|
| 50 | import Util |
|---|
| 51 | |
|---|
| 52 | import UniqSupply ( UniqSupply, mkSplitUniqSupply, splitUniqSupply ) |
|---|
| 53 | import Outputable |
|---|
| 54 | import Control.Monad |
|---|
| 55 | |
|---|
| 56 | #ifdef GHCI |
|---|
| 57 | import Type ( mkTyConTy ) |
|---|
| 58 | import RdrName ( mkRdrQual ) |
|---|
| 59 | import OccName ( mkVarOcc ) |
|---|
| 60 | import PrelNames ( pluginTyConName ) |
|---|
| 61 | import DynamicLoading ( forceLoadTyCon, lookupRdrNameInModule, getValueSafely ) |
|---|
| 62 | import Module ( ModuleName ) |
|---|
| 63 | import Panic |
|---|
| 64 | #endif |
|---|
| 65 | \end{code} |
|---|
| 66 | |
|---|
| 67 | %************************************************************************ |
|---|
| 68 | %* * |
|---|
| 69 | \subsection{The driver for the simplifier} |
|---|
| 70 | %* * |
|---|
| 71 | %************************************************************************ |
|---|
| 72 | |
|---|
| 73 | \begin{code} |
|---|
| 74 | core2core :: HscEnv -> ModGuts -> IO ModGuts |
|---|
| 75 | core2core hsc_env guts |
|---|
| 76 | = do { us <- mkSplitUniqSupply 's' |
|---|
| 77 | -- make sure all plugins are loaded |
|---|
| 78 | |
|---|
| 79 | ; let builtin_passes = getCoreToDo dflags |
|---|
| 80 | ; |
|---|
| 81 | ; (guts2, stats) <- runCoreM hsc_env hpt_rule_base us mod $ |
|---|
| 82 | do { all_passes <- addPluginPasses dflags builtin_passes |
|---|
| 83 | ; runCorePasses all_passes guts } |
|---|
| 84 | |
|---|
| 85 | {-- |
|---|
| 86 | ; Err.dumpIfSet_dyn dflags Opt_D_dump_core_pipeline |
|---|
| 87 | "Plugin information" "" -- TODO FIXME: dump plugin info |
|---|
| 88 | --} |
|---|
| 89 | ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_stats |
|---|
| 90 | "Grand total simplifier statistics" |
|---|
| 91 | (pprSimplCount stats) |
|---|
| 92 | |
|---|
| 93 | ; return guts2 } |
|---|
| 94 | where |
|---|
| 95 | dflags = hsc_dflags hsc_env |
|---|
| 96 | home_pkg_rules = hptRules hsc_env (dep_mods (mg_deps guts)) |
|---|
| 97 | hpt_rule_base = mkRuleBase home_pkg_rules |
|---|
| 98 | mod = mg_module guts |
|---|
| 99 | -- mod: get the module out of the current HscEnv so we can retrieve it from the monad. |
|---|
| 100 | -- This is very convienent for the users of the monad (e.g. plugins do not have to |
|---|
| 101 | -- consume the ModGuts to find the module) but somewhat ugly because mg_module may |
|---|
| 102 | -- _theoretically_ be changed during the Core pipeline (it's part of ModGuts), which |
|---|
| 103 | -- would mean our cached value would go out of date. |
|---|
| 104 | \end{code} |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | %************************************************************************ |
|---|
| 108 | %* * |
|---|
| 109 | Generating the main optimisation pipeline |
|---|
| 110 | %* * |
|---|
| 111 | %************************************************************************ |
|---|
| 112 | |
|---|
| 113 | \begin{code} |
|---|
| 114 | getCoreToDo :: DynFlags -> [CoreToDo] |
|---|
| 115 | getCoreToDo dflags |
|---|
| 116 | = core_todo |
|---|
| 117 | where |
|---|
| 118 | opt_level = optLevel dflags |
|---|
| 119 | phases = simplPhases dflags |
|---|
| 120 | max_iter = maxSimplIterations dflags |
|---|
| 121 | rule_check = ruleCheck dflags |
|---|
| 122 | strictness = dopt Opt_Strictness dflags |
|---|
| 123 | full_laziness = dopt Opt_FullLaziness dflags |
|---|
| 124 | do_specialise = dopt Opt_Specialise dflags |
|---|
| 125 | do_float_in = dopt Opt_FloatIn dflags |
|---|
| 126 | cse = dopt Opt_CSE dflags |
|---|
| 127 | spec_constr = dopt Opt_SpecConstr dflags |
|---|
| 128 | liberate_case = dopt Opt_LiberateCase dflags |
|---|
| 129 | static_args = dopt Opt_StaticArgumentTransformation dflags |
|---|
| 130 | rules_on = dopt Opt_EnableRewriteRules dflags |
|---|
| 131 | eta_expand_on = dopt Opt_DoLambdaEtaExpansion dflags |
|---|
| 132 | |
|---|
| 133 | maybe_rule_check phase = runMaybe rule_check (CoreDoRuleCheck phase) |
|---|
| 134 | |
|---|
| 135 | maybe_strictness_before phase |
|---|
| 136 | = runWhen (phase `elem` strictnessBefore dflags) CoreDoStrictness |
|---|
| 137 | |
|---|
| 138 | base_mode = SimplMode { sm_phase = panic "base_mode" |
|---|
| 139 | , sm_names = [] |
|---|
| 140 | , sm_rules = rules_on |
|---|
| 141 | , sm_eta_expand = eta_expand_on |
|---|
| 142 | , sm_inline = True |
|---|
| 143 | , sm_case_case = True } |
|---|
| 144 | |
|---|
| 145 | simpl_phase phase names iter |
|---|
| 146 | = CoreDoPasses |
|---|
| 147 | $ [ maybe_strictness_before phase |
|---|
| 148 | , CoreDoSimplify iter |
|---|
| 149 | (base_mode { sm_phase = Phase phase |
|---|
| 150 | , sm_names = names }) |
|---|
| 151 | |
|---|
| 152 | , maybe_rule_check (Phase phase) ] |
|---|
| 153 | |
|---|
| 154 | -- Vectorisation can introduce a fair few common sub expressions involving |
|---|
| 155 | -- DPH primitives. For example, see the Reverse test from dph-examples. |
|---|
| 156 | -- We need to eliminate these common sub expressions before their definitions |
|---|
| 157 | -- are inlined in phase 2. The CSE introduces lots of v1 = v2 bindings, |
|---|
| 158 | -- so we also run simpl_gently to inline them. |
|---|
| 159 | ++ (if dopt Opt_Vectorise dflags && phase == 3 |
|---|
| 160 | then [CoreCSE, simpl_gently] |
|---|
| 161 | else []) |
|---|
| 162 | |
|---|
| 163 | vectorisation |
|---|
| 164 | = runWhen (dopt Opt_Vectorise dflags) $ |
|---|
| 165 | CoreDoPasses [ simpl_gently, CoreDoVectorisation ] |
|---|
| 166 | |
|---|
| 167 | -- By default, we have 2 phases before phase 0. |
|---|
| 168 | |
|---|
| 169 | -- Want to run with inline phase 2 after the specialiser to give |
|---|
| 170 | -- maximum chance for fusion to work before we inline build/augment |
|---|
| 171 | -- in phase 1. This made a difference in 'ansi' where an |
|---|
| 172 | -- overloaded function wasn't inlined till too late. |
|---|
| 173 | |
|---|
| 174 | -- Need phase 1 so that build/augment get |
|---|
| 175 | -- inlined. I found that spectral/hartel/genfft lost some useful |
|---|
| 176 | -- strictness in the function sumcode' if augment is not inlined |
|---|
| 177 | -- before strictness analysis runs |
|---|
| 178 | simpl_phases = CoreDoPasses [ simpl_phase phase ["main"] max_iter |
|---|
| 179 | | phase <- [phases, phases-1 .. 1] ] |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | -- initial simplify: mk specialiser happy: minimum effort please |
|---|
| 183 | simpl_gently = CoreDoSimplify max_iter |
|---|
| 184 | (base_mode { sm_phase = InitialPhase |
|---|
| 185 | , sm_names = ["Gentle"] |
|---|
| 186 | , sm_rules = rules_on -- Note [RULEs enabled in SimplGently] |
|---|
| 187 | , sm_inline = False |
|---|
| 188 | , sm_case_case = False }) |
|---|
| 189 | -- Don't do case-of-case transformations. |
|---|
| 190 | -- This makes full laziness work better |
|---|
| 191 | |
|---|
| 192 | core_todo = |
|---|
| 193 | if opt_level == 0 then |
|---|
| 194 | [ vectorisation |
|---|
| 195 | , CoreDoSimplify max_iter |
|---|
| 196 | (base_mode { sm_phase = Phase 0 |
|---|
| 197 | , sm_names = ["Non-opt simplification"] }) |
|---|
| 198 | ] |
|---|
| 199 | |
|---|
| 200 | else {- opt_level >= 1 -} [ |
|---|
| 201 | |
|---|
| 202 | -- We want to do the static argument transform before full laziness as it |
|---|
| 203 | -- may expose extra opportunities to float things outwards. However, to fix |
|---|
| 204 | -- up the output of the transformation we need at do at least one simplify |
|---|
| 205 | -- after this before anything else |
|---|
| 206 | runWhen static_args (CoreDoPasses [ simpl_gently, CoreDoStaticArgs ]), |
|---|
| 207 | |
|---|
| 208 | -- We run vectorisation here for now, but we might also try to run |
|---|
| 209 | -- it later |
|---|
| 210 | vectorisation, |
|---|
| 211 | |
|---|
| 212 | -- initial simplify: mk specialiser happy: minimum effort please |
|---|
| 213 | simpl_gently, |
|---|
| 214 | |
|---|
| 215 | -- Specialisation is best done before full laziness |
|---|
| 216 | -- so that overloaded functions have all their dictionary lambdas manifest |
|---|
| 217 | runWhen do_specialise CoreDoSpecialising, |
|---|
| 218 | |
|---|
| 219 | runWhen full_laziness $ |
|---|
| 220 | CoreDoFloatOutwards FloatOutSwitches { |
|---|
| 221 | floatOutLambdas = Just 0, |
|---|
| 222 | floatOutConstants = True, |
|---|
| 223 | floatOutPartialApplications = False }, |
|---|
| 224 | -- Was: gentleFloatOutSwitches |
|---|
| 225 | -- |
|---|
| 226 | -- I have no idea why, but not floating constants to |
|---|
| 227 | -- top level is very bad in some cases. |
|---|
| 228 | -- |
|---|
| 229 | -- Notably: p_ident in spectral/rewrite |
|---|
| 230 | -- Changing from "gentle" to "constantsOnly" |
|---|
| 231 | -- improved rewrite's allocation by 19%, and |
|---|
| 232 | -- made 0.0% difference to any other nofib |
|---|
| 233 | -- benchmark |
|---|
| 234 | -- |
|---|
| 235 | -- Not doing floatOutPartialApplications yet, we'll do |
|---|
| 236 | -- that later on when we've had a chance to get more |
|---|
| 237 | -- accurate arity information. In fact it makes no |
|---|
| 238 | -- difference at all to performance if we do it here, |
|---|
| 239 | -- but maybe we save some unnecessary to-and-fro in |
|---|
| 240 | -- the simplifier. |
|---|
| 241 | |
|---|
| 242 | runWhen do_float_in CoreDoFloatInwards, |
|---|
| 243 | |
|---|
| 244 | simpl_phases, |
|---|
| 245 | |
|---|
| 246 | -- Phase 0: allow all Ids to be inlined now |
|---|
| 247 | -- This gets foldr inlined before strictness analysis |
|---|
| 248 | |
|---|
| 249 | -- At least 3 iterations because otherwise we land up with |
|---|
| 250 | -- huge dead expressions because of an infelicity in the |
|---|
| 251 | -- simpifier. |
|---|
| 252 | -- let k = BIG in foldr k z xs |
|---|
| 253 | -- ==> let k = BIG in letrec go = \xs -> ...(k x).... in go xs |
|---|
| 254 | -- ==> let k = BIG in letrec go = \xs -> ...(BIG x).... in go xs |
|---|
| 255 | -- Don't stop now! |
|---|
| 256 | simpl_phase 0 ["main"] (max max_iter 3), |
|---|
| 257 | |
|---|
| 258 | runWhen strictness (CoreDoPasses [ |
|---|
| 259 | CoreDoStrictness, |
|---|
| 260 | CoreDoWorkerWrapper, |
|---|
| 261 | simpl_phase 0 ["post-worker-wrapper"] max_iter |
|---|
| 262 | ]), |
|---|
| 263 | |
|---|
| 264 | runWhen full_laziness $ |
|---|
| 265 | CoreDoFloatOutwards FloatOutSwitches { |
|---|
| 266 | floatOutLambdas = floatLamArgs dflags, |
|---|
| 267 | floatOutConstants = True, |
|---|
| 268 | floatOutPartialApplications = True }, |
|---|
| 269 | -- nofib/spectral/hartel/wang doubles in speed if you |
|---|
| 270 | -- do full laziness late in the day. It only happens |
|---|
| 271 | -- after fusion and other stuff, so the early pass doesn't |
|---|
| 272 | -- catch it. For the record, the redex is |
|---|
| 273 | -- f_el22 (f_el21 r_midblock) |
|---|
| 274 | |
|---|
| 275 | |
|---|
| 276 | runWhen cse CoreCSE, |
|---|
| 277 | -- We want CSE to follow the final full-laziness pass, because it may |
|---|
| 278 | -- succeed in commoning up things floated out by full laziness. |
|---|
| 279 | -- CSE used to rely on the no-shadowing invariant, but it doesn't any more |
|---|
| 280 | |
|---|
| 281 | runWhen do_float_in CoreDoFloatInwards, |
|---|
| 282 | |
|---|
| 283 | maybe_rule_check (Phase 0), |
|---|
| 284 | |
|---|
| 285 | -- Case-liberation for -O2. This should be after |
|---|
| 286 | -- strictness analysis and the simplification which follows it. |
|---|
| 287 | runWhen liberate_case (CoreDoPasses [ |
|---|
| 288 | CoreLiberateCase, |
|---|
| 289 | simpl_phase 0 ["post-liberate-case"] max_iter |
|---|
| 290 | ]), -- Run the simplifier after LiberateCase to vastly |
|---|
| 291 | -- reduce the possiblility of shadowing |
|---|
| 292 | -- Reason: see Note [Shadowing] in SpecConstr.lhs |
|---|
| 293 | |
|---|
| 294 | runWhen spec_constr CoreDoSpecConstr, |
|---|
| 295 | |
|---|
| 296 | maybe_rule_check (Phase 0), |
|---|
| 297 | |
|---|
| 298 | -- Final clean-up simplification: |
|---|
| 299 | simpl_phase 0 ["final"] max_iter |
|---|
| 300 | ] |
|---|
| 301 | \end{code} |
|---|
| 302 | |
|---|
| 303 | Loading plugins |
|---|
| 304 | |
|---|
| 305 | \begin{code} |
|---|
| 306 | addPluginPasses :: DynFlags -> [CoreToDo] -> CoreM [CoreToDo] |
|---|
| 307 | #ifndef GHCI |
|---|
| 308 | addPluginPasses _ builtin_passes = return builtin_passes |
|---|
| 309 | #else |
|---|
| 310 | addPluginPasses dflags builtin_passes |
|---|
| 311 | = do { hsc_env <- getHscEnv |
|---|
| 312 | ; named_plugins <- liftIO (loadPlugins hsc_env) |
|---|
| 313 | ; foldM query_plug builtin_passes named_plugins } |
|---|
| 314 | where |
|---|
| 315 | query_plug todos (mod_nm, plug) |
|---|
| 316 | = installCoreToDos plug options todos |
|---|
| 317 | where |
|---|
| 318 | options = [ option | (opt_mod_nm, option) <- pluginModNameOpts dflags |
|---|
| 319 | , opt_mod_nm == mod_nm ] |
|---|
| 320 | |
|---|
| 321 | loadPlugins :: HscEnv -> IO [(ModuleName, Plugin)] |
|---|
| 322 | loadPlugins hsc_env |
|---|
| 323 | = do { let to_load = pluginModNames (hsc_dflags hsc_env) |
|---|
| 324 | ; plugins <- mapM (loadPlugin hsc_env) to_load |
|---|
| 325 | ; return $ to_load `zip` plugins } |
|---|
| 326 | |
|---|
| 327 | loadPlugin :: HscEnv -> ModuleName -> IO Plugin |
|---|
| 328 | loadPlugin hsc_env mod_name |
|---|
| 329 | = do { let plugin_rdr_name = mkRdrQual mod_name (mkVarOcc "plugin") |
|---|
| 330 | ; mb_name <- lookupRdrNameInModule hsc_env mod_name plugin_rdr_name |
|---|
| 331 | ; case mb_name of { |
|---|
| 332 | Nothing -> throwGhcException (CmdLineError $ showSDoc $ hsep |
|---|
| 333 | [ ptext (sLit "The module"), ppr mod_name |
|---|
| 334 | , ptext (sLit "did not export the plugin name") |
|---|
| 335 | , ppr plugin_rdr_name ]) ; |
|---|
| 336 | Just name -> |
|---|
| 337 | |
|---|
| 338 | do { plugin_tycon <- forceLoadTyCon hsc_env pluginTyConName |
|---|
| 339 | ; mb_plugin <- getValueSafely hsc_env name (mkTyConTy plugin_tycon) |
|---|
| 340 | ; case mb_plugin of |
|---|
| 341 | Nothing -> throwGhcException (CmdLineError $ showSDoc $ hsep |
|---|
| 342 | [ ptext (sLit "The value"), ppr name |
|---|
| 343 | , ptext (sLit "did not have the type") |
|---|
| 344 | , ppr pluginTyConName, ptext (sLit "as required")]) |
|---|
| 345 | Just plugin -> return plugin } } } |
|---|
| 346 | #endif |
|---|
| 347 | \end{code} |
|---|
| 348 | |
|---|
| 349 | %************************************************************************ |
|---|
| 350 | %* * |
|---|
| 351 | The CoreToDo interpreter |
|---|
| 352 | %* * |
|---|
| 353 | %************************************************************************ |
|---|
| 354 | |
|---|
| 355 | \begin{code} |
|---|
| 356 | runCorePasses :: [CoreToDo] -> ModGuts -> CoreM ModGuts |
|---|
| 357 | runCorePasses passes guts |
|---|
| 358 | = foldM do_pass guts passes |
|---|
| 359 | where |
|---|
| 360 | do_pass guts CoreDoNothing = return guts |
|---|
| 361 | do_pass guts (CoreDoPasses ps) = runCorePasses ps guts |
|---|
| 362 | do_pass guts pass |
|---|
| 363 | = do { dflags <- getDynFlags |
|---|
| 364 | ; liftIO $ showPass dflags pass |
|---|
| 365 | ; guts' <- doCorePass pass guts |
|---|
| 366 | ; liftIO $ endPass dflags pass (mg_binds guts') (mg_rules guts') |
|---|
| 367 | ; return guts' } |
|---|
| 368 | |
|---|
| 369 | doCorePass :: CoreToDo -> ModGuts -> CoreM ModGuts |
|---|
| 370 | doCorePass pass@(CoreDoSimplify {}) = {-# SCC "Simplify" #-} |
|---|
| 371 | simplifyPgm pass |
|---|
| 372 | |
|---|
| 373 | doCorePass CoreCSE = {-# SCC "CommonSubExpr" #-} |
|---|
| 374 | doPass cseProgram |
|---|
| 375 | |
|---|
| 376 | doCorePass CoreLiberateCase = {-# SCC "LiberateCase" #-} |
|---|
| 377 | doPassD liberateCase |
|---|
| 378 | |
|---|
| 379 | doCorePass CoreDoFloatInwards = {-# SCC "FloatInwards" #-} |
|---|
| 380 | doPass floatInwards |
|---|
| 381 | |
|---|
| 382 | doCorePass (CoreDoFloatOutwards f) = {-# SCC "FloatOutwards" #-} |
|---|
| 383 | doPassDUM (floatOutwards f) |
|---|
| 384 | |
|---|
| 385 | doCorePass CoreDoStaticArgs = {-# SCC "StaticArgs" #-} |
|---|
| 386 | doPassU doStaticArgs |
|---|
| 387 | |
|---|
| 388 | doCorePass CoreDoStrictness = {-# SCC "Stranal" #-} |
|---|
| 389 | doPassDM dmdAnalPgm |
|---|
| 390 | |
|---|
| 391 | doCorePass CoreDoWorkerWrapper = {-# SCC "WorkWrap" #-} |
|---|
| 392 | doPassU wwTopBinds |
|---|
| 393 | |
|---|
| 394 | doCorePass CoreDoSpecialising = {-# SCC "Specialise" #-} |
|---|
| 395 | specProgram |
|---|
| 396 | |
|---|
| 397 | doCorePass CoreDoSpecConstr = {-# SCC "SpecConstr" #-} |
|---|
| 398 | specConstrProgram |
|---|
| 399 | |
|---|
| 400 | doCorePass CoreDoVectorisation = {-# SCC "Vectorise" #-} |
|---|
| 401 | vectorise |
|---|
| 402 | |
|---|
| 403 | doCorePass CoreDoPrintCore = observe printCore |
|---|
| 404 | doCorePass (CoreDoRuleCheck phase pat) = ruleCheckPass phase pat |
|---|
| 405 | doCorePass CoreDoNothing = return |
|---|
| 406 | doCorePass (CoreDoPasses passes) = runCorePasses passes |
|---|
| 407 | |
|---|
| 408 | #ifdef GHCI |
|---|
| 409 | doCorePass (CoreDoPluginPass _ pass) = {-# SCC "Plugin" #-} pass |
|---|
| 410 | #endif |
|---|
| 411 | |
|---|
| 412 | doCorePass pass = pprPanic "doCorePass" (ppr pass) |
|---|
| 413 | \end{code} |
|---|
| 414 | |
|---|
| 415 | %************************************************************************ |
|---|
| 416 | %* * |
|---|
| 417 | \subsection{Core pass combinators} |
|---|
| 418 | %* * |
|---|
| 419 | %************************************************************************ |
|---|
| 420 | |
|---|
| 421 | \begin{code} |
|---|
| 422 | printCore :: a -> CoreProgram -> IO () |
|---|
| 423 | printCore _ binds = Err.dumpIfSet True "Print Core" (pprCoreBindings binds) |
|---|
| 424 | |
|---|
| 425 | ruleCheckPass :: CompilerPhase -> String -> ModGuts -> CoreM ModGuts |
|---|
| 426 | ruleCheckPass current_phase pat guts = do |
|---|
| 427 | rb <- getRuleBase |
|---|
| 428 | dflags <- getDynFlags |
|---|
| 429 | liftIO $ Err.showPass dflags "RuleCheck" |
|---|
| 430 | liftIO $ printDump (ruleCheckProgram current_phase pat rb (mg_binds guts)) |
|---|
| 431 | return guts |
|---|
| 432 | |
|---|
| 433 | |
|---|
| 434 | doPassDUM :: (DynFlags -> UniqSupply -> CoreProgram -> IO CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 435 | doPassDUM do_pass = doPassM $ \binds -> do |
|---|
| 436 | dflags <- getDynFlags |
|---|
| 437 | us <- getUniqueSupplyM |
|---|
| 438 | liftIO $ do_pass dflags us binds |
|---|
| 439 | |
|---|
| 440 | doPassDM :: (DynFlags -> CoreProgram -> IO CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 441 | doPassDM do_pass = doPassDUM (\dflags -> const (do_pass dflags)) |
|---|
| 442 | |
|---|
| 443 | doPassD :: (DynFlags -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 444 | doPassD do_pass = doPassDM (\dflags -> return . do_pass dflags) |
|---|
| 445 | |
|---|
| 446 | doPassDU :: (DynFlags -> UniqSupply -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 447 | doPassDU do_pass = doPassDUM (\dflags us -> return . do_pass dflags us) |
|---|
| 448 | |
|---|
| 449 | doPassU :: (UniqSupply -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 450 | doPassU do_pass = doPassDU (const do_pass) |
|---|
| 451 | |
|---|
| 452 | -- Most passes return no stats and don't change rules: these combinators |
|---|
| 453 | -- let us lift them to the full blown ModGuts+CoreM world |
|---|
| 454 | doPassM :: Monad m => (CoreProgram -> m CoreProgram) -> ModGuts -> m ModGuts |
|---|
| 455 | doPassM bind_f guts = do |
|---|
| 456 | binds' <- bind_f (mg_binds guts) |
|---|
| 457 | return (guts { mg_binds = binds' }) |
|---|
| 458 | |
|---|
| 459 | doPass :: (CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts |
|---|
| 460 | doPass bind_f guts = return $ guts { mg_binds = bind_f (mg_binds guts) } |
|---|
| 461 | |
|---|
| 462 | -- Observer passes just peek; don't modify the bindings at all |
|---|
| 463 | observe :: (DynFlags -> CoreProgram -> IO a) -> ModGuts -> CoreM ModGuts |
|---|
| 464 | observe do_pass = doPassM $ \binds -> do |
|---|
| 465 | dflags <- getDynFlags |
|---|
| 466 | _ <- liftIO $ do_pass dflags binds |
|---|
| 467 | return binds |
|---|
| 468 | \end{code} |
|---|
| 469 | |
|---|
| 470 | |
|---|
| 471 | %************************************************************************ |
|---|
| 472 | %* * |
|---|
| 473 | Gentle simplification |
|---|
| 474 | %* * |
|---|
| 475 | %************************************************************************ |
|---|
| 476 | |
|---|
| 477 | \begin{code} |
|---|
| 478 | simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do |
|---|
| 479 | -> CoreExpr |
|---|
| 480 | -> IO CoreExpr |
|---|
| 481 | -- simplifyExpr is called by the driver to simplify an |
|---|
| 482 | -- expression typed in at the interactive prompt |
|---|
| 483 | -- |
|---|
| 484 | -- Also used by Template Haskell |
|---|
| 485 | simplifyExpr dflags expr |
|---|
| 486 | = do { |
|---|
| 487 | ; Err.showPass dflags "Simplify" |
|---|
| 488 | |
|---|
| 489 | ; us <- mkSplitUniqSupply 's' |
|---|
| 490 | |
|---|
| 491 | ; let sz = exprSize expr |
|---|
| 492 | (expr', counts) = initSmpl dflags emptyRuleBase emptyFamInstEnvs us sz $ |
|---|
| 493 | simplExprGently (simplEnvForGHCi dflags) expr |
|---|
| 494 | |
|---|
| 495 | ; Err.dumpIfSet (dopt Opt_D_dump_simpl_stats dflags) |
|---|
| 496 | "Simplifier statistics" (pprSimplCount counts) |
|---|
| 497 | |
|---|
| 498 | ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression" |
|---|
| 499 | (pprCoreExpr expr') |
|---|
| 500 | |
|---|
| 501 | ; return expr' |
|---|
| 502 | } |
|---|
| 503 | |
|---|
| 504 | simplExprGently :: SimplEnv -> CoreExpr -> SimplM CoreExpr |
|---|
| 505 | -- Simplifies an expression |
|---|
| 506 | -- does occurrence analysis, then simplification |
|---|
| 507 | -- and repeats (twice currently) because one pass |
|---|
| 508 | -- alone leaves tons of crud. |
|---|
| 509 | -- Used (a) for user expressions typed in at the interactive prompt |
|---|
| 510 | -- (b) the LHS and RHS of a RULE |
|---|
| 511 | -- (c) Template Haskell splices |
|---|
| 512 | -- |
|---|
| 513 | -- The name 'Gently' suggests that the SimplifierMode is SimplGently, |
|---|
| 514 | -- and in fact that is so.... but the 'Gently' in simplExprGently doesn't |
|---|
| 515 | -- enforce that; it just simplifies the expression twice |
|---|
| 516 | |
|---|
| 517 | -- It's important that simplExprGently does eta reduction; see |
|---|
| 518 | -- Note [Simplifying the left-hand side of a RULE] above. The |
|---|
| 519 | -- simplifier does indeed do eta reduction (it's in Simplify.completeLam) |
|---|
| 520 | -- but only if -O is on. |
|---|
| 521 | |
|---|
| 522 | simplExprGently env expr = do |
|---|
| 523 | expr1 <- simplExpr env (occurAnalyseExpr expr) |
|---|
| 524 | simplExpr env (occurAnalyseExpr expr1) |
|---|
| 525 | \end{code} |
|---|
| 526 | |
|---|
| 527 | |
|---|
| 528 | %************************************************************************ |
|---|
| 529 | %* * |
|---|
| 530 | \subsection{The driver for the simplifier} |
|---|
| 531 | %* * |
|---|
| 532 | %************************************************************************ |
|---|
| 533 | |
|---|
| 534 | \begin{code} |
|---|
| 535 | simplifyPgm :: CoreToDo -> ModGuts -> CoreM ModGuts |
|---|
| 536 | simplifyPgm pass guts |
|---|
| 537 | = do { hsc_env <- getHscEnv |
|---|
| 538 | ; us <- getUniqueSupplyM |
|---|
| 539 | ; rb <- getRuleBase |
|---|
| 540 | ; liftIOWithCount $ |
|---|
| 541 | simplifyPgmIO pass hsc_env us rb guts } |
|---|
| 542 | |
|---|
| 543 | simplifyPgmIO :: CoreToDo |
|---|
| 544 | -> HscEnv |
|---|
| 545 | -> UniqSupply |
|---|
| 546 | -> RuleBase |
|---|
| 547 | -> ModGuts |
|---|
| 548 | -> IO (SimplCount, ModGuts) -- New bindings |
|---|
| 549 | |
|---|
| 550 | simplifyPgmIO pass@(CoreDoSimplify max_iterations mode) |
|---|
| 551 | hsc_env us hpt_rule_base |
|---|
| 552 | guts@(ModGuts { mg_module = this_mod |
|---|
| 553 | , mg_binds = binds, mg_rules = rules |
|---|
| 554 | , mg_fam_inst_env = fam_inst_env }) |
|---|
| 555 | = do { (termination_msg, it_count, counts_out, guts') |
|---|
| 556 | <- do_iteration us 1 [] binds rules |
|---|
| 557 | |
|---|
| 558 | ; Err.dumpIfSet (dump_phase && dopt Opt_D_dump_simpl_stats dflags) |
|---|
| 559 | "Simplifier statistics for following pass" |
|---|
| 560 | (vcat [text termination_msg <+> text "after" <+> ppr it_count <+> text "iterations", |
|---|
| 561 | blankLine, |
|---|
| 562 | pprSimplCount counts_out]) |
|---|
| 563 | |
|---|
| 564 | ; return (counts_out, guts') |
|---|
| 565 | } |
|---|
| 566 | where |
|---|
| 567 | dflags = hsc_dflags hsc_env |
|---|
| 568 | dump_phase = dumpSimplPhase dflags mode |
|---|
| 569 | simpl_env = mkSimplEnv mode |
|---|
| 570 | active_rule = activeRule simpl_env |
|---|
| 571 | |
|---|
| 572 | do_iteration :: UniqSupply |
|---|
| 573 | -> Int -- Counts iterations |
|---|
| 574 | -> [SimplCount] -- Counts from earlier iterations, reversed |
|---|
| 575 | -> CoreProgram -- Bindings in |
|---|
| 576 | -> [CoreRule] -- and orphan rules |
|---|
| 577 | -> IO (String, Int, SimplCount, ModGuts) |
|---|
| 578 | |
|---|
| 579 | do_iteration us iteration_no counts_so_far binds rules |
|---|
| 580 | -- iteration_no is the number of the iteration we are |
|---|
| 581 | -- about to begin, with '1' for the first |
|---|
| 582 | | iteration_no > max_iterations -- Stop if we've run out of iterations |
|---|
| 583 | = WARN( debugIsOn && (max_iterations > 2) |
|---|
| 584 | , hang (ptext (sLit "Simplifier baling out after") <+> int max_iterations |
|---|
| 585 | <+> ptext (sLit "iterations") |
|---|
| 586 | <+> (brackets $ hsep $ punctuate comma $ |
|---|
| 587 | map (int . simplCountN) (reverse counts_so_far))) |
|---|
| 588 | 2 (ptext (sLit "Size =") <+> ppr (coreBindsStats binds))) |
|---|
| 589 | |
|---|
| 590 | -- Subtract 1 from iteration_no to get the |
|---|
| 591 | -- number of iterations we actually completed |
|---|
| 592 | return ( "Simplifier baled out", iteration_no - 1 |
|---|
| 593 | , totalise counts_so_far |
|---|
| 594 | , guts { mg_binds = binds, mg_rules = rules } ) |
|---|
| 595 | |
|---|
| 596 | -- Try and force thunks off the binds; significantly reduces |
|---|
| 597 | -- space usage, especially with -O. JRS, 000620. |
|---|
| 598 | | let sz = coreBindsSize binds |
|---|
| 599 | , sz == sz -- Force it |
|---|
| 600 | = do { |
|---|
| 601 | -- Occurrence analysis |
|---|
| 602 | let { -- During the 'InitialPhase' (i.e., before vectorisation), we need to make sure |
|---|
| 603 | -- that the right-hand sides of vectorisation declarations are taken into |
|---|
| 604 | -- account during occurence analysis. |
|---|
| 605 | maybeVects = case sm_phase mode of |
|---|
| 606 | InitialPhase -> mg_vect_decls guts |
|---|
| 607 | _ -> [] |
|---|
| 608 | ; tagged_binds = {-# SCC "OccAnal" #-} |
|---|
| 609 | occurAnalysePgm this_mod active_rule rules maybeVects binds |
|---|
| 610 | } ; |
|---|
| 611 | Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis" |
|---|
| 612 | (pprCoreBindings tagged_binds); |
|---|
| 613 | |
|---|
| 614 | -- Get any new rules, and extend the rule base |
|---|
| 615 | -- See Note [Overall plumbing for rules] in Rules.lhs |
|---|
| 616 | -- We need to do this regularly, because simplification can |
|---|
| 617 | -- poke on IdInfo thunks, which in turn brings in new rules |
|---|
| 618 | -- behind the scenes. Otherwise there's a danger we'll simply |
|---|
| 619 | -- miss the rules for Ids hidden inside imported inlinings |
|---|
| 620 | eps <- hscEPS hsc_env ; |
|---|
| 621 | let { rule_base1 = unionRuleBase hpt_rule_base (eps_rule_base eps) |
|---|
| 622 | ; rule_base2 = extendRuleBaseList rule_base1 rules |
|---|
| 623 | ; simpl_binds = {-# SCC "SimplTopBinds" #-} |
|---|
| 624 | simplTopBinds simpl_env tagged_binds |
|---|
| 625 | ; fam_envs = (eps_fam_inst_env eps, fam_inst_env) } ; |
|---|
| 626 | |
|---|
| 627 | -- Simplify the program |
|---|
| 628 | -- We do this with a *case* not a *let* because lazy pattern |
|---|
| 629 | -- matching bit us with bad space leak! |
|---|
| 630 | -- With a let, we ended up with |
|---|
| 631 | -- let |
|---|
| 632 | -- t = initSmpl ... |
|---|
| 633 | -- counts1 = snd t |
|---|
| 634 | -- in |
|---|
| 635 | -- case t of {(_,counts1) -> if counts1=0 then ... } |
|---|
| 636 | -- So the conditional didn't force counts1, because the |
|---|
| 637 | -- selection got duplicated. Sigh! |
|---|
| 638 | case initSmpl dflags rule_base2 fam_envs us1 sz simpl_binds of { |
|---|
| 639 | (env1, counts1) -> do { |
|---|
| 640 | |
|---|
| 641 | let { binds1 = getFloatBinds env1 |
|---|
| 642 | ; rules1 = substRulesForImportedIds (mkCoreSubst (text "imp-rules") env1) rules |
|---|
| 643 | } ; |
|---|
| 644 | |
|---|
| 645 | -- Stop if nothing happened; don't dump output |
|---|
| 646 | if isZeroSimplCount counts1 then |
|---|
| 647 | return ( "Simplifier reached fixed point", iteration_no |
|---|
| 648 | , totalise (counts1 : counts_so_far) -- Include "free" ticks |
|---|
| 649 | , guts { mg_binds = binds1, mg_rules = rules1 } ) |
|---|
| 650 | else do { |
|---|
| 651 | -- Short out indirections |
|---|
| 652 | -- We do this *after* at least one run of the simplifier |
|---|
| 653 | -- because indirection-shorting uses the export flag on *occurrences* |
|---|
| 654 | -- and that isn't guaranteed to be ok until after the first run propagates |
|---|
| 655 | -- stuff from the binding site to its occurrences |
|---|
| 656 | -- |
|---|
| 657 | -- ToDo: alas, this means that indirection-shorting does not happen at all |
|---|
| 658 | -- if the simplifier does nothing (not common, I know, but unsavoury) |
|---|
| 659 | let { binds2 = {-# SCC "ZapInd" #-} shortOutIndirections binds1 } ; |
|---|
| 660 | |
|---|
| 661 | -- Dump the result of this iteration |
|---|
| 662 | end_iteration dflags pass iteration_no counts1 binds2 rules1 ; |
|---|
| 663 | |
|---|
| 664 | -- Loop |
|---|
| 665 | do_iteration us2 (iteration_no + 1) (counts1:counts_so_far) binds2 rules1 |
|---|
| 666 | } } } } |
|---|
| 667 | | otherwise = panic "do_iteration" |
|---|
| 668 | where |
|---|
| 669 | (us1, us2) = splitUniqSupply us |
|---|
| 670 | |
|---|
| 671 | -- Remember the counts_so_far are reversed |
|---|
| 672 | totalise :: [SimplCount] -> SimplCount |
|---|
| 673 | totalise = foldr (\c acc -> acc `plusSimplCount` c) |
|---|
| 674 | (zeroSimplCount dflags) |
|---|
| 675 | |
|---|
| 676 | simplifyPgmIO _ _ _ _ _ = panic "simplifyPgmIO" |
|---|
| 677 | |
|---|
| 678 | ------------------- |
|---|
| 679 | end_iteration :: DynFlags -> CoreToDo -> Int |
|---|
| 680 | -> SimplCount -> CoreProgram -> [CoreRule] -> IO () |
|---|
| 681 | end_iteration dflags pass iteration_no counts binds rules |
|---|
| 682 | = do { dumpPassResult dflags mb_flag hdr pp_counts binds rules |
|---|
| 683 | ; lintPassResult dflags pass binds } |
|---|
| 684 | where |
|---|
| 685 | mb_flag | dopt Opt_D_dump_simpl_iterations dflags = Just Opt_D_dump_simpl_phases |
|---|
| 686 | | otherwise = Nothing |
|---|
| 687 | -- Show details if Opt_D_dump_simpl_iterations is on |
|---|
| 688 | |
|---|
| 689 | hdr = ptext (sLit "Simplifier iteration=") <> int iteration_no |
|---|
| 690 | pp_counts = vcat [ ptext (sLit "---- Simplifier counts for") <+> hdr |
|---|
| 691 | , pprSimplCount counts |
|---|
| 692 | , ptext (sLit "---- End of simplifier counts for") <+> hdr ] |
|---|
| 693 | \end{code} |
|---|
| 694 | |
|---|
| 695 | |
|---|
| 696 | %************************************************************************ |
|---|
| 697 | %* * |
|---|
| 698 | Shorting out indirections |
|---|
| 699 | %* * |
|---|
| 700 | %************************************************************************ |
|---|
| 701 | |
|---|
| 702 | If we have this: |
|---|
| 703 | |
|---|
| 704 | x_local = <expression> |
|---|
| 705 | ...bindings... |
|---|
| 706 | x_exported = x_local |
|---|
| 707 | |
|---|
| 708 | where x_exported is exported, and x_local is not, then we replace it with this: |
|---|
| 709 | |
|---|
| 710 | x_exported = <expression> |
|---|
| 711 | x_local = x_exported |
|---|
| 712 | ...bindings... |
|---|
| 713 | |
|---|
| 714 | Without this we never get rid of the x_exported = x_local thing. This |
|---|
| 715 | save a gratuitous jump (from \tr{x_exported} to \tr{x_local}), and |
|---|
| 716 | makes strictness information propagate better. This used to happen in |
|---|
| 717 | the final phase, but it's tidier to do it here. |
|---|
| 718 | |
|---|
| 719 | Note [Transferring IdInfo] |
|---|
| 720 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 721 | We want to propagage any useful IdInfo on x_local to x_exported. |
|---|
| 722 | |
|---|
| 723 | STRICTNESS: if we have done strictness analysis, we want the strictness info on |
|---|
| 724 | x_local to transfer to x_exported. Hence the copyIdInfo call. |
|---|
| 725 | |
|---|
| 726 | RULES: we want to *add* any RULES for x_local to x_exported. |
|---|
| 727 | |
|---|
| 728 | |
|---|
| 729 | Note [Messing up the exported Id's RULES] |
|---|
| 730 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 731 | We must be careful about discarding (obviously) or even merging the |
|---|
| 732 | RULES on the exported Id. The example that went bad on me at one stage |
|---|
| 733 | was this one: |
|---|
| 734 | |
|---|
| 735 | iterate :: (a -> a) -> a -> [a] |
|---|
| 736 | [Exported] |
|---|
| 737 | iterate = iterateList |
|---|
| 738 | |
|---|
| 739 | iterateFB c f x = x `c` iterateFB c f (f x) |
|---|
| 740 | iterateList f x = x : iterateList f (f x) |
|---|
| 741 | [Not exported] |
|---|
| 742 | |
|---|
| 743 | {-# RULES |
|---|
| 744 | "iterate" forall f x. iterate f x = build (\c _n -> iterateFB c f x) |
|---|
| 745 | "iterateFB" iterateFB (:) = iterateList |
|---|
| 746 | #-} |
|---|
| 747 | |
|---|
| 748 | This got shorted out to: |
|---|
| 749 | |
|---|
| 750 | iterateList :: (a -> a) -> a -> [a] |
|---|
| 751 | iterateList = iterate |
|---|
| 752 | |
|---|
| 753 | iterateFB c f x = x `c` iterateFB c f (f x) |
|---|
| 754 | iterate f x = x : iterate f (f x) |
|---|
| 755 | |
|---|
| 756 | {-# RULES |
|---|
| 757 | "iterate" forall f x. iterate f x = build (\c _n -> iterateFB c f x) |
|---|
| 758 | "iterateFB" iterateFB (:) = iterate |
|---|
| 759 | #-} |
|---|
| 760 | |
|---|
| 761 | And now we get an infinite loop in the rule system |
|---|
| 762 | iterate f x -> build (\cn -> iterateFB c f x) |
|---|
| 763 | -> iterateFB (:) f x |
|---|
| 764 | -> iterate f x |
|---|
| 765 | |
|---|
| 766 | Old "solution": |
|---|
| 767 | use rule switching-off pragmas to get rid |
|---|
| 768 | of iterateList in the first place |
|---|
| 769 | |
|---|
| 770 | But in principle the user *might* want rules that only apply to the Id |
|---|
| 771 | he says. And inline pragmas are similar |
|---|
| 772 | {-# NOINLINE f #-} |
|---|
| 773 | f = local |
|---|
| 774 | local = <stuff> |
|---|
| 775 | Then we do not want to get rid of the NOINLINE. |
|---|
| 776 | |
|---|
| 777 | Hence hasShortableIdinfo. |
|---|
| 778 | |
|---|
| 779 | |
|---|
| 780 | Note [Rules and indirection-zapping] |
|---|
| 781 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 782 | Problem: what if x_exported has a RULE that mentions something in ...bindings...? |
|---|
| 783 | Then the things mentioned can be out of scope! Solution |
|---|
| 784 | a) Make sure that in this pass the usage-info from x_exported is |
|---|
| 785 | available for ...bindings... |
|---|
| 786 | b) If there are any such RULES, rec-ify the entire top-level. |
|---|
| 787 | It'll get sorted out next time round |
|---|
| 788 | |
|---|
| 789 | Other remarks |
|---|
| 790 | ~~~~~~~~~~~~~ |
|---|
| 791 | If more than one exported thing is equal to a local thing (i.e., the |
|---|
| 792 | local thing really is shared), then we do one only: |
|---|
| 793 | \begin{verbatim} |
|---|
| 794 | x_local = .... |
|---|
| 795 | x_exported1 = x_local |
|---|
| 796 | x_exported2 = x_local |
|---|
| 797 | ==> |
|---|
| 798 | x_exported1 = .... |
|---|
| 799 | |
|---|
| 800 | x_exported2 = x_exported1 |
|---|
| 801 | \end{verbatim} |
|---|
| 802 | |
|---|
| 803 | We rely on prior eta reduction to simplify things like |
|---|
| 804 | \begin{verbatim} |
|---|
| 805 | x_exported = /\ tyvars -> x_local tyvars |
|---|
| 806 | ==> |
|---|
| 807 | x_exported = x_local |
|---|
| 808 | \end{verbatim} |
|---|
| 809 | Hence,there's a possibility of leaving unchanged something like this: |
|---|
| 810 | \begin{verbatim} |
|---|
| 811 | x_local = .... |
|---|
| 812 | x_exported1 = x_local Int |
|---|
| 813 | \end{verbatim} |
|---|
| 814 | By the time we've thrown away the types in STG land this |
|---|
| 815 | could be eliminated. But I don't think it's very common |
|---|
| 816 | and it's dangerous to do this fiddling in STG land |
|---|
| 817 | because we might elminate a binding that's mentioned in the |
|---|
| 818 | unfolding for something. |
|---|
| 819 | |
|---|
| 820 | \begin{code} |
|---|
| 821 | type IndEnv = IdEnv Id -- Maps local_id -> exported_id |
|---|
| 822 | |
|---|
| 823 | shortOutIndirections :: CoreProgram -> CoreProgram |
|---|
| 824 | shortOutIndirections binds |
|---|
| 825 | | isEmptyVarEnv ind_env = binds |
|---|
| 826 | | no_need_to_flatten = binds' -- See Note [Rules and indirect-zapping] |
|---|
| 827 | | otherwise = [Rec (flattenBinds binds')] -- for this no_need_to_flatten stuff |
|---|
| 828 | where |
|---|
| 829 | ind_env = makeIndEnv binds |
|---|
| 830 | exp_ids = varSetElems ind_env -- These exported Ids are the subjects |
|---|
| 831 | exp_id_set = mkVarSet exp_ids -- of the indirection-elimination |
|---|
| 832 | no_need_to_flatten = all (null . specInfoRules . idSpecialisation) exp_ids |
|---|
| 833 | binds' = concatMap zap binds |
|---|
| 834 | |
|---|
| 835 | zap (NonRec bndr rhs) = [NonRec b r | (b,r) <- zapPair (bndr,rhs)] |
|---|
| 836 | zap (Rec pairs) = [Rec (concatMap zapPair pairs)] |
|---|
| 837 | |
|---|
| 838 | zapPair (bndr, rhs) |
|---|
| 839 | | bndr `elemVarSet` exp_id_set = [] |
|---|
| 840 | | Just exp_id <- lookupVarEnv ind_env bndr = [(transferIdInfo exp_id bndr, rhs), |
|---|
| 841 | (bndr, Var exp_id)] |
|---|
| 842 | | otherwise = [(bndr,rhs)] |
|---|
| 843 | |
|---|
| 844 | makeIndEnv :: [CoreBind] -> IndEnv |
|---|
| 845 | makeIndEnv binds |
|---|
| 846 | = foldr add_bind emptyVarEnv binds |
|---|
| 847 | where |
|---|
| 848 | add_bind :: CoreBind -> IndEnv -> IndEnv |
|---|
| 849 | add_bind (NonRec exported_id rhs) env = add_pair (exported_id, rhs) env |
|---|
| 850 | add_bind (Rec pairs) env = foldr add_pair env pairs |
|---|
| 851 | |
|---|
| 852 | add_pair :: (Id,CoreExpr) -> IndEnv -> IndEnv |
|---|
| 853 | add_pair (exported_id, Var local_id) env |
|---|
| 854 | | shortMeOut env exported_id local_id = extendVarEnv env local_id exported_id |
|---|
| 855 | add_pair _ env = env |
|---|
| 856 | |
|---|
| 857 | ----------------- |
|---|
| 858 | shortMeOut :: IndEnv -> Id -> Id -> Bool |
|---|
| 859 | shortMeOut ind_env exported_id local_id |
|---|
| 860 | -- The if-then-else stuff is just so I can get a pprTrace to see |
|---|
| 861 | -- how often I don't get shorting out becuase of IdInfo stuff |
|---|
| 862 | = if isExportedId exported_id && -- Only if this is exported |
|---|
| 863 | |
|---|
| 864 | isLocalId local_id && -- Only if this one is defined in this |
|---|
| 865 | -- module, so that we *can* change its |
|---|
| 866 | -- binding to be the exported thing! |
|---|
| 867 | |
|---|
| 868 | not (isExportedId local_id) && -- Only if this one is not itself exported, |
|---|
| 869 | -- since the transformation will nuke it |
|---|
| 870 | |
|---|
| 871 | not (local_id `elemVarEnv` ind_env) -- Only if not already substituted for |
|---|
| 872 | then |
|---|
| 873 | if hasShortableIdInfo exported_id |
|---|
| 874 | then True -- See Note [Messing up the exported Id's IdInfo] |
|---|
| 875 | else WARN( True, ptext (sLit "Not shorting out:") <+> ppr exported_id ) |
|---|
| 876 | False |
|---|
| 877 | else |
|---|
| 878 | False |
|---|
| 879 | |
|---|
| 880 | ----------------- |
|---|
| 881 | hasShortableIdInfo :: Id -> Bool |
|---|
| 882 | -- True if there is no user-attached IdInfo on exported_id, |
|---|
| 883 | -- so we can safely discard it |
|---|
| 884 | -- See Note [Messing up the exported Id's IdInfo] |
|---|
| 885 | hasShortableIdInfo id |
|---|
| 886 | = isEmptySpecInfo (specInfo info) |
|---|
| 887 | && isDefaultInlinePragma (inlinePragInfo info) |
|---|
| 888 | && not (isStableUnfolding (unfoldingInfo info)) |
|---|
| 889 | where |
|---|
| 890 | info = idInfo id |
|---|
| 891 | |
|---|
| 892 | ----------------- |
|---|
| 893 | transferIdInfo :: Id -> Id -> Id |
|---|
| 894 | -- See Note [Transferring IdInfo] |
|---|
| 895 | -- If we have |
|---|
| 896 | -- lcl_id = e; exp_id = lcl_id |
|---|
| 897 | -- and lcl_id has useful IdInfo, we don't want to discard it by going |
|---|
| 898 | -- gbl_id = e; lcl_id = gbl_id |
|---|
| 899 | -- Instead, transfer IdInfo from lcl_id to exp_id |
|---|
| 900 | -- Overwriting, rather than merging, seems to work ok. |
|---|
| 901 | transferIdInfo exported_id local_id |
|---|
| 902 | = modifyIdInfo transfer exported_id |
|---|
| 903 | where |
|---|
| 904 | local_info = idInfo local_id |
|---|
| 905 | transfer exp_info = exp_info `setStrictnessInfo` strictnessInfo local_info |
|---|
| 906 | `setUnfoldingInfo` unfoldingInfo local_info |
|---|
| 907 | `setInlinePragInfo` inlinePragInfo local_info |
|---|
| 908 | `setSpecInfo` addSpecInfo (specInfo exp_info) new_info |
|---|
| 909 | new_info = setSpecInfoHead (idName exported_id) |
|---|
| 910 | (specInfo local_info) |
|---|
| 911 | -- Remember to set the function-name field of the |
|---|
| 912 | -- rules as we transfer them from one function to another |
|---|
| 913 | \end{code} |
|---|