diff options
author | Sebastian Graf <sebastian.graf@kit.edu> | 2019-01-28 16:49:04 +0100 |
---|---|---|
committer | Sebastian Graf <sebastian.graf@kit.edu> | 2020-02-12 11:00:58 +0100 |
commit | 059c3c9d7c84fc37c69e9f414ff736d47081e72c (patch) | |
tree | da3c17ac002b9c6d31542af78553769fd40d5d65 /compiler/simplCore | |
parent | f0c0ee7d9a942a19361e72553cd08f42cc12b04a (diff) | |
download | haskell-059c3c9d7c84fc37c69e9f414ff736d47081e72c.tar.gz |
Separate CPR analysis from the Demand analyserwip/sep-cpr
The reasons for that can be found in the wiki:
https://gitlab.haskell.org/ghc/ghc/wikis/nested-cpr/split-off-cpr
We now run CPR after demand analysis (except for after the final demand
analysis run just before code gen). CPR got its own dump flags
(`-ddump-cpr-anal`, `-ddump-cpr-signatures`), but not its own flag to
activate/deactivate. It will run with `-fstrictness`/`-fworker-wrapper`.
As explained on the wiki page, this step is necessary for a sane Nested
CPR analysis. And it has quite positive impact on compiler performance:
Metric Decrease:
T9233
T9675
T9961
T15263
Diffstat (limited to 'compiler/simplCore')
-rw-r--r-- | compiler/simplCore/CallArity.hs | 2 | ||||
-rw-r--r-- | compiler/simplCore/CoreMonad.hs | 6 | ||||
-rw-r--r-- | compiler/simplCore/SetLevels.hs | 2 | ||||
-rw-r--r-- | compiler/simplCore/SimplCore.hs | 21 | ||||
-rw-r--r-- | compiler/simplCore/SimplUtils.hs | 4 | ||||
-rw-r--r-- | compiler/simplCore/Simplify.hs | 12 |
6 files changed, 29 insertions, 18 deletions
diff --git a/compiler/simplCore/CallArity.hs b/compiler/simplCore/CallArity.hs index 75c55c698c..d3709ac82a 100644 --- a/compiler/simplCore/CallArity.hs +++ b/compiler/simplCore/CallArity.hs @@ -701,7 +701,7 @@ trimArity v a = minimum [a, max_arity_by_type, max_arity_by_strsig] where max_arity_by_type = length (typeArity (idType v)) max_arity_by_strsig - | isBotRes result_info = length demands + | isBotDiv result_info = length demands | otherwise = a (demands, result_info) = splitStrictSig (idStrictness v) diff --git a/compiler/simplCore/CoreMonad.hs b/compiler/simplCore/CoreMonad.hs index 672b56e64f..24567cb1c3 100644 --- a/compiler/simplCore/CoreMonad.hs +++ b/compiler/simplCore/CoreMonad.hs @@ -107,7 +107,8 @@ data CoreToDo -- These are diff core-to-core passes, | CoreDoStaticArgs | CoreDoCallArity | CoreDoExitify - | CoreDoStrictness + | CoreDoDemand + | CoreDoCpr | CoreDoWorkerWrapper | CoreDoSpecialising | CoreDoSpecConstr @@ -134,7 +135,8 @@ instance Outputable CoreToDo where ppr CoreDoStaticArgs = text "Static argument" ppr CoreDoCallArity = text "Called arity analysis" ppr CoreDoExitify = text "Exitification transformation" - ppr CoreDoStrictness = text "Demand analysis" + ppr CoreDoDemand = text "Demand analysis" + ppr CoreDoCpr = text "Constructed Product Result analysis" ppr CoreDoWorkerWrapper = text "Worker Wrapper binds" ppr CoreDoSpecialising = text "Specialise" ppr CoreDoSpecConstr = text "SpecConstr" diff --git a/compiler/simplCore/SetLevels.hs b/compiler/simplCore/SetLevels.hs index 7cf0b9d524..8f70df9d79 100644 --- a/compiler/simplCore/SetLevels.hs +++ b/compiler/simplCore/SetLevels.hs @@ -88,6 +88,7 @@ import UniqDSet ( getUniqDSet ) import VarEnv import Literal ( litIsTrivial ) import Demand ( StrictSig, Demand, isStrictDmd, splitStrictSig, increaseStrictSigArity ) +import Cpr ( mkCprSig, botCpr ) import Name ( getOccName, mkSystemVarName ) import OccName ( occNameString ) import Type ( Type, mkLamTypes, splitTyConApp_maybe, tyCoVarsOfType @@ -983,6 +984,7 @@ annotateBotStr id n_extra mb_str Nothing -> id Just (arity, sig) -> id `setIdArity` (arity + n_extra) `setIdStrictness` (increaseStrictSigArity n_extra sig) + `setIdCprInfo` mkCprSig (arity + n_extra) botCpr notWorthFloating :: CoreExpr -> [Var] -> Bool -- Returns True if the expression would be replaced by diff --git a/compiler/simplCore/SimplCore.hs b/compiler/simplCore/SimplCore.hs index 026631df37..4c7e509f4c 100644 --- a/compiler/simplCore/SimplCore.hs +++ b/compiler/simplCore/SimplCore.hs @@ -45,6 +45,7 @@ import SAT ( doStaticArgs ) import Specialise ( specProgram) import SpecConstr ( specConstrProgram) import DmdAnal ( dmdAnalProgram ) +import CprAnal ( cprAnalProgram ) import CallArity ( callArityAnalProgram ) import Exitify ( exitifyProgram ) import WorkWrap ( wwTopBinds ) @@ -141,7 +142,7 @@ getCoreToDo dflags maybe_rule_check phase = runMaybe rule_check (CoreDoRuleCheck phase) maybe_strictness_before phase - = runWhen (phase `elem` strictnessBefore dflags) CoreDoStrictness + = runWhen (phase `elem` strictnessBefore dflags) CoreDoDemand base_mode = SimplMode { sm_phase = panic "base_mode" , sm_names = [] @@ -175,14 +176,12 @@ getCoreToDo dflags -- Don't do case-of-case transformations. -- This makes full laziness work better - strictness_pass = if ww_on - then [CoreDoStrictness,CoreDoWorkerWrapper] - else [CoreDoStrictness] + dmd_cpr_ww = if ww_on then [CoreDoDemand,CoreDoCpr,CoreDoWorkerWrapper] + else [CoreDoDemand,CoreDoCpr] - -- New demand analyser demand_analyser = (CoreDoPasses ( - strictness_pass ++ + dmd_cpr_ww ++ [simpl_phase 0 ["post-worker-wrapper"] max_iter] )) @@ -332,7 +331,7 @@ getCoreToDo dflags simpl_phase 0 ["final"] max_iter, runWhen late_dmd_anal $ CoreDoPasses ( - strictness_pass ++ + dmd_cpr_ww ++ [simpl_phase 0 ["post-late-ww"] max_iter] ), @@ -341,7 +340,7 @@ getCoreToDo dflags -- has run at all. See Note [Final Demand Analyser run] in DmdAnal -- It is EXTREMELY IMPORTANT to run this pass, otherwise execution -- can become /exponentially/ more expensive. See #11731, #12996. - runWhen (strictness || late_dmd_anal) CoreDoStrictness, + runWhen (strictness || late_dmd_anal) CoreDoDemand, maybe_rule_check (Phase 0) ] @@ -445,9 +444,12 @@ doCorePass CoreDoCallArity = {-# SCC "CallArity" #-} doCorePass CoreDoExitify = {-# SCC "Exitify" #-} doPass exitifyProgram -doCorePass CoreDoStrictness = {-# SCC "NewStranal" #-} +doCorePass CoreDoDemand = {-# SCC "DmdAnal" #-} doPassDFM dmdAnalProgram +doCorePass CoreDoCpr = {-# SCC "CprAnal" #-} + doPassDFM cprAnalProgram + doCorePass CoreDoWorkerWrapper = {-# SCC "WorkWrap" #-} doPassDFU wwTopBinds @@ -1020,6 +1022,7 @@ transferIdInfo exported_id local_id where local_info = idInfo local_id transfer exp_info = exp_info `setStrictnessInfo` strictnessInfo local_info + `setCprInfo` cprInfo local_info `setUnfoldingInfo` unfoldingInfo local_info `setInlinePragInfo` inlinePragInfo local_info `setRuleInfo` addRuleInfo (ruleInfo exp_info) new_info diff --git a/compiler/simplCore/SimplUtils.hs b/compiler/simplCore/SimplUtils.hs index 5c653c7adb..03c4b8ebd6 100644 --- a/compiler/simplCore/SimplUtils.hs +++ b/compiler/simplCore/SimplUtils.hs @@ -499,7 +499,7 @@ mkArgInfo env fun rules n_val_args call_cont -- top-level bindings for (say) strings into -- calls to error. But now we are more careful about -- inlining lone variables, so its ok (see SimplUtils.analyseCont) - if isBotRes result_info then + if isBotDiv result_info then map isStrictDmd demands -- Finite => result is bottom else map isStrictDmd demands ++ vanilla_stricts @@ -1575,7 +1575,7 @@ arguments! Note [Do not eta-expand join points] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Similarly to CPR (see Note [Don't CPR join points] in WorkWrap), a join point +Similarly to CPR (see Note [Don't w/w join points for CPR] in WorkWrap), a join point stands well to gain from its outer binding's eta-expansion, and eta-expanding a join point is fraught with issues like how to deal with a cast: diff --git a/compiler/simplCore/Simplify.hs b/compiler/simplCore/Simplify.hs index 01d802c30b..50d35149d5 100644 --- a/compiler/simplCore/Simplify.hs +++ b/compiler/simplCore/Simplify.hs @@ -35,14 +35,15 @@ import DataCon ( DataCon, dataConWorkId, dataConRepStrictness , StrictnessMark (..) ) import CoreMonad ( Tick(..), SimplMode(..) ) import CoreSyn -import Demand ( StrictSig(..), dmdTypeDepth, isStrictDmd ) +import Demand ( StrictSig(..), dmdTypeDepth, isStrictDmd + , mkClosedStrictSig, topDmd, botDiv ) +import Cpr ( mkCprSig, botCpr ) import PprCore ( pprCoreExpr ) import CoreUnfold import CoreUtils import CoreOpt ( pushCoTyArg, pushCoValArg , joinPointBinding_maybe, joinPointBindings_maybe ) import Rules ( mkRuleInfo, lookupRule, getRules ) -import Demand ( mkClosedStrictSig, topDmd, botRes ) import BasicTypes ( TopLevelFlag(..), isNotTopLevel, isTopLevel, RecFlag(..), Arity ) import MonadUtils ( mapAccumLM, liftIO ) @@ -447,6 +448,7 @@ prepareRhs mode top_lvl occ info (Cast rhs co) -- Note [Float coercions] ; return (floats, Cast rhs' co) } where sanitised_info = vanillaIdInfo `setStrictnessInfo` strictnessInfo info + `setCprInfo` cprInfo info `setDemandInfo` demandInfo info prepareRhs mode top_lvl occ _ rhs0 @@ -731,8 +733,10 @@ addLetBndrInfo new_bndr new_arity is_bot new_unf = info2 -- Bottoming bindings: see Note [Bottoming bindings] - info4 | is_bot = info3 `setStrictnessInfo` - mkClosedStrictSig (replicate new_arity topDmd) botRes + info4 | is_bot = info3 + `setStrictnessInfo` + mkClosedStrictSig (replicate new_arity topDmd) botDiv + `setCprInfo` mkCprSig new_arity botCpr | otherwise = info3 -- Zap call arity info. We have used it by now (via |