summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Opt/Simplify.hs
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2020-08-24 14:36:57 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2020-09-21 16:15:14 +0100
commitff5a843e2003abed15f99d10eb1195cf9d572e06 (patch)
tree74e015a51530a05adb25daab808f97dd5b050a54 /compiler/GHC/Core/Opt/Simplify.hs
parent9df77fed8918bb335874a584a829ee32325cefb5 (diff)
downloadhaskell-wip/T18223.tar.gz
Better eta-expansion (again) and don't specilise DFunswip/T18223
This patch fixes #18223, which made GHC generate an exponential amount of code. There are three quite separate changes in here 1. Re-engineer eta-expansion (again). The eta-expander was generating lots of intermediate stuff, which could be optimised away, but which choked the simplifier meanwhile. Relatively easy to kill it off at source. See Note [The EtaInfo mechanism] in GHC.Core.Opt.Arity. The main new thing is the use of pushCoArg in getArg_maybe. 2. Stop Specialise specalising DFuns. This is the cause of a huge (and utterly unnecessary) blowup in program size in #18223. See Note [Do not specialise DFuns] in GHC.Core.Opt.Specialise. I also refactored the Specialise monad a bit... it was silly, because it passed on unchanging values as if they were mutable state. 3. Do an extra Simplifer run, after SpecConstra and before late-Specialise. I found (investigating perf/compiler/T16473) that failing to do this was crippling *both* SpecConstr *and* Specialise. See Note [Simplify after SpecConstr] in GHC.Core.Opt.Pipeline. This change does mean an extra run of the Simplifier, but only with -O2, and I think that's acceptable. T16473 allocates *three* times less with this change. (I changed it to check runtime rather than compile time.) Some smaller consequences * I moved pushCoercion, pushCoArg and friends from SimpleOpt to Arity, because it was needed by the new etaInfoApp. And pushCoValArg now returns a MCoercion rather than Coercion for the argument Coercion. * A minor, incidental improvement to Core pretty-printing This does fix #18223, (which was otherwise uncompilable. Hooray. But there is still a big intermediate because there are some very deeply nested types in that program. Modest reductions in compile-time allocation on a couple of benchmarks T12425 -2.0% T13253 -10.3% Metric increase with -O2, due to extra simplifier run T9233 +5.8% T12227 +1.8% T15630 +5.0% There is a spurious apparent increase on heap residency on T9630, on some architectures at least. I tried it with -G1 and the residency is essentially unchanged. Metric Increase T9233 T12227 T9630 Metric Decrease T12425 T13253
Diffstat (limited to 'compiler/GHC/Core/Opt/Simplify.hs')
-rw-r--r--compiler/GHC/Core/Opt/Simplify.hs38
1 files changed, 22 insertions, 16 deletions
diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs
index e219a0dba9..6c207766bd 100644
--- a/compiler/GHC/Core/Opt/Simplify.hs
+++ b/compiler/GHC/Core/Opt/Simplify.hs
@@ -51,9 +51,9 @@ import GHC.Core.Unfold
import GHC.Core.Unfold.Make
import GHC.Core.Utils
import GHC.Core.Opt.Arity ( ArityType(..), arityTypeArity, isBotArityType
+ , pushCoTyArg, pushCoValArg
, idArityType, etaExpandAT )
-import GHC.Core.SimpleOpt ( pushCoTyArg, pushCoValArg
- , joinPointBinding_maybe, joinPointBindings_maybe )
+import GHC.Core.SimpleOpt ( joinPointBinding_maybe, joinPointBindings_maybe )
import GHC.Core.FVs ( mkRuleInfo )
import GHC.Core.Rules ( lookupRule, getRules, initRuleOpts )
import GHC.Types.Basic
@@ -318,7 +318,7 @@ simplLazyBind env top_lvl is_rec bndr bndr1 rhs rhs_se
; let rhs_cont = mkRhsStop (substTy body_env (exprType body))
; (body_floats0, body0) <- {-#SCC "simplExprF" #-} simplExprF body_env body rhs_cont
- -- Never float join-floats out of a non-join let-binding
+ -- Never float join-floats out of a non-join let-binding (which this is)
-- So wrap the body in the join-floats right now
-- Hence: body_floats1 consists only of let-floats
; let (body_floats1, body1) = wrapJoinFloatsX body_floats0 body0
@@ -1414,25 +1414,23 @@ simplCast env body co0 cont0
-- type of the hole changes (#16312)
-- (f |> co) e ===> (f (e |> co1)) |> co2
- -- where co :: (s1->s2) ~ (t1~t2)
+ -- where co :: (s1->s2) ~ (t1->t2)
-- co1 :: t1 ~ s1
-- co2 :: s2 ~ t2
addCoerce co cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se
, sc_dup = dup, sc_cont = tail })
- | Just (co1, m_co2) <- pushCoValArg co
- , let new_ty = coercionRKind co1
- , not (isTypeLevPoly new_ty) -- Without this check, we get a lev-poly arg
- -- See Note [Levity polymorphism invariants] in GHC.Core
- -- test: typecheck/should_run/EtaExpandLevPoly
+ | Just (m_co1, m_co2) <- pushCoValArg co
+ , levity_ok m_co1
= {-#SCC "addCoerce-pushCoValArg" #-}
do { tail' <- addCoerceM m_co2 tail
- ; if isReflCo co1
- then return (cont { sc_cont = tail'
- , sc_hole_ty = coercionLKind co })
+ ; case m_co1 of {
+ MRefl -> return (cont { sc_cont = tail'
+ , sc_hole_ty = coercionLKind co }) ;
-- Avoid simplifying if possible;
-- See Note [Avoiding exponential behaviour]
- else do
- { (dup', arg_se', arg') <- simplArg env dup arg_se arg
+
+ MCo co1 ->
+ do { (dup', arg_se', arg') <- simplArg env dup arg_se arg
-- When we build the ApplyTo we can't mix the OutCoercion
-- 'co' with the InExpr 'arg', so we simplify
-- to make it all consistent. It's a bit messy.
@@ -1442,7 +1440,7 @@ simplCast env body co0 cont0
, sc_env = arg_se'
, sc_dup = dup'
, sc_cont = tail'
- , sc_hole_ty = coercionLKind co }) } }
+ , sc_hole_ty = coercionLKind co }) } } }
addCoerce co cont
| isReflexiveCo co = return cont -- Having this at the end makes a huge
@@ -1450,6 +1448,13 @@ simplCast env body co0 cont0
-- See Note [Optimising reflexivity]
| otherwise = return (CastIt co cont)
+ levity_ok :: MCoercionR -> Bool
+ levity_ok MRefl = True
+ levity_ok (MCo co) = not $ isTypeLevPoly $ coercionRKind co
+ -- Without this check, we get a lev-poly arg
+ -- See Note [Levity polymorphism invariants] in GHC.Core
+ -- test: typecheck/should_run/EtaExpandLevPoly
+
simplArg :: SimplEnv -> DupFlag -> StaticEnv -> CoreExpr
-> SimplM (DupFlag, StaticEnv, OutExpr)
simplArg env dup_flag arg_env arg
@@ -3114,7 +3119,7 @@ knownCon :: SimplEnv
knownCon env scrut dc_floats dc dc_ty_args dc_args bndr bs rhs cont
= do { (floats1, env1) <- bind_args env bs dc_args
- ; (floats2, env2) <- bind_case_bndr env1
+ ; (floats2, env2) <- bind_case_bndr env1
; (floats3, expr') <- simplExprF env2 rhs cont
; case dc_floats of
[] ->
@@ -3240,6 +3245,7 @@ altsWouldDup [_] = False
altsWouldDup (alt:alts)
| is_bot_alt alt = altsWouldDup alts
| otherwise = not (all is_bot_alt alts)
+ -- otherwise case: first alt is non-bot, so all the rest must be bot
where
is_bot_alt (_,_,rhs) = exprIsDeadEnd rhs