diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2020-08-24 14:36:57 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-09-22 05:37:24 -0400 |
commit | 6de40f83c53c3b1899f7b4912badbe98e4fbde88 (patch) | |
tree | 9a311c2630a5ecd66abcee3a02ce8efef7364262 /testsuite | |
parent | aaa51dcfdb729f130aeefeaeac15029b62096a74 (diff) | |
download | haskell-6de40f83c53c3b1899f7b4912badbe98e4fbde88.tar.gz |
Better eta-expansion (again) and don't specilise DFuns
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 'testsuite')
-rw-r--r-- | testsuite/tests/perf/compiler/Makefile | 4 | ||||
-rw-r--r-- | testsuite/tests/perf/compiler/T16473.stdout | 98 | ||||
-rw-r--r-- | testsuite/tests/perf/compiler/T18223.hs | 78 | ||||
-rw-r--r-- | testsuite/tests/perf/compiler/all.T | 13 | ||||
-rw-r--r-- | testsuite/tests/printer/T18052a.stderr | 2 | ||||
-rw-r--r-- | testsuite/tests/simplCore/should_compile/T17966.stdout | 3 | ||||
-rw-r--r-- | testsuite/tests/stranal/should_compile/T18122.stderr | 40 |
7 files changed, 111 insertions, 127 deletions
diff --git a/testsuite/tests/perf/compiler/Makefile b/testsuite/tests/perf/compiler/Makefile index b27c842e91..ded99684b3 100644 --- a/testsuite/tests/perf/compiler/Makefile +++ b/testsuite/tests/perf/compiler/Makefile @@ -7,7 +7,3 @@ T4007: $(RM) -f T4007.hi T4007.o '$(TEST_HC)' $(TEST_HC_OPTS) -c -O -ddump-rule-firings T4007.hs -T16473: - $(RM) -f T16473.hi T16473.o - '$(TEST_HC)' $(TEST_HC_OPTS) -c -O -ddump-rule-firings T16473.hs - diff --git a/testsuite/tests/perf/compiler/T16473.stdout b/testsuite/tests/perf/compiler/T16473.stdout index e6063e01e8..c3ac783e70 100644 --- a/testsuite/tests/perf/compiler/T16473.stdout +++ b/testsuite/tests/perf/compiler/T16473.stdout @@ -1,97 +1 @@ -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op liftA2 (BUILTIN) -Rule fired: Class op <*> (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: Class op <$ (BUILTIN) -Rule fired: Class op <*> (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op get (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op >> (BUILTIN) -Rule fired: Class op put (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op get (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op >> (BUILTIN) -Rule fired: Class op put (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op show (BUILTIN) -Rule fired: Class op mempty (BUILTIN) -Rule fired: Class op fromInteger (BUILTIN) -Rule fired: Integer -> Int# (BUILTIN) -Rule fired: Class op <> (BUILTIN) -Rule fired: Class op + (BUILTIN) -Rule fired: Class op enumFromTo (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op *> (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: fold/build (GHC.Base) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: ># (BUILTIN) -Rule fired: ==# (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op <*> (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op pure (BUILTIN) -Rule fired: Class op $p1Monad (BUILTIN) -Rule fired: Class op $p1Applicative (BUILTIN) -Rule fired: SPEC/Main $fMonadStateT_$c>>= @Identity _ (Main) -Rule fired: SPEC/Main $fApplicativeStateT_$c<*> @Identity _ (Main) -Rule fired: SPEC/Main $fApplicativeStateT_$cpure @Identity _ (Main) -Rule fired: SPEC/Main $fFunctorStateT @Identity _ (Main) -Rule fired: SPEC/Main $fFunctorStateT_$cfmap @Identity _ (Main) -Rule fired: Class op fmap (BUILTIN) -Rule fired: SPEC/Main $fFunctorStateT_$cfmap @Identity _ (Main) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op fmap (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op return (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op >>= (BUILTIN) -Rule fired: Class op return (BUILTIN) +5050 diff --git a/testsuite/tests/perf/compiler/T18223.hs b/testsuite/tests/perf/compiler/T18223.hs new file mode 100644 index 0000000000..3e160cc957 --- /dev/null +++ b/testsuite/tests/perf/compiler/T18223.hs @@ -0,0 +1,78 @@ +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE Strict #-} + +import Control.Monad.State + +tester :: MonadState a m => m () +tester = modify' id + +-- manyState :: StateT () (StateT () IO) () -> IO () +-- manyState :: _ -> IO () +manyState x = + (flip evalStateT () -- 1 + . flip evalStateT () -- 2 + . flip evalStateT () -- 3 + . flip evalStateT () -- 4 + . flip evalStateT () -- 5 + . flip evalStateT () -- 6 + . flip evalStateT () -- 7 + . flip evalStateT () -- 8 + . flip evalStateT () -- 9 + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + . flip evalStateT () + ) x :: IO () + +main :: IO () +main = manyState tester >>= print diff --git a/testsuite/tests/perf/compiler/all.T b/testsuite/tests/perf/compiler/all.T index a8eea78729..f6e56c56b3 100644 --- a/testsuite/tests/perf/compiler/all.T +++ b/testsuite/tests/perf/compiler/all.T @@ -367,7 +367,13 @@ test('T16190', multimod_compile, ['T16190.hs', '-v0']) -test('T16473', normal, makefile_test, ['T16473']) +# Run this program. If specialisation fails, it'll start to allocate much more +test ('T16473', + [ collect_stats('bytes allocated',5) + , only_ways(['normal']) + ], + compile_and_run, + ['-O2 -flate-specialise']) test('T17516', [ collect_compiler_stats('bytes allocated', 5), @@ -415,3 +421,8 @@ test ('T13253-spj', ], compile, ['-v0 -O']) +test ('T18223', + [ collect_compiler_stats('bytes allocated',2) + ], + compile, + ['-v0 -O']) diff --git a/testsuite/tests/printer/T18052a.stderr b/testsuite/tests/printer/T18052a.stderr index a45c9c958c..d8d9f94ba3 100644 --- a/testsuite/tests/printer/T18052a.stderr +++ b/testsuite/tests/printer/T18052a.stderr @@ -20,7 +20,7 @@ T18052a.$b:||: = \ (@a) (@b) (x :: a) (y :: b) -> (x, y) -- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0} (+++) :: forall {a}. [a] -> [a] -> [a] [GblId] -(+++) = (++) +(+++) = ++ -- RHS size: {terms: 13, types: 20, coercions: 0, joins: 0/0} T18052a.$m:||: diff --git a/testsuite/tests/simplCore/should_compile/T17966.stdout b/testsuite/tests/simplCore/should_compile/T17966.stdout index dc34ec8fae..9abaee2af2 100644 --- a/testsuite/tests/simplCore/should_compile/T17966.stdout +++ b/testsuite/tests/simplCore/should_compile/T17966.stdout @@ -1,5 +1,2 @@ RULES: "SPEC $cm @()" [0] RULES: "SPEC f @Bool @() @(Maybe Integer)" [0] -"SPEC/T17966 $fShowMaybe_$cshow @Integer" -"SPEC/T17966 $fShowMaybe_$cshowList @Integer" -"SPEC/T17966 $fShowMaybe @Integer" diff --git a/testsuite/tests/stranal/should_compile/T18122.stderr b/testsuite/tests/stranal/should_compile/T18122.stderr index ff18350279..f94751fb55 100644 --- a/testsuite/tests/stranal/should_compile/T18122.stderr +++ b/testsuite/tests/stranal/should_compile/T18122.stderr @@ -13,9 +13,8 @@ Lib.$trModule4 = "main"# -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0} Lib.$trModule3 :: GHC.Types.TrName [GblId, - Cpr=m1, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, - WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}] + WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}] Lib.$trModule3 = GHC.Types.TrNameS Lib.$trModule4 -- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0} @@ -28,27 +27,25 @@ Lib.$trModule2 = "Lib"# -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0} Lib.$trModule1 :: GHC.Types.TrName [GblId, - Cpr=m1, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, - WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}] + WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}] Lib.$trModule1 = GHC.Types.TrNameS Lib.$trModule2 -- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0} Lib.$trModule :: GHC.Types.Module [GblId, - Cpr=m1, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, - WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 30}] + WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}] Lib.$trModule = GHC.Types.Module Lib.$trModule3 Lib.$trModule1 -- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0} Lib.$wfoo [InlPrag=NOINLINE] :: GHC.Prim.Int# -> GHC.Prim.Int# -> GHC.Prim.Int# [GblId, Arity=2, Str=<L,U><L,U>, Unf=OtherCon []] -Lib.$wfoo = (GHC.Prim.+#) +Lib.$wfoo = GHC.Prim.+# -- RHS size: {terms: 18, types: 14, coercions: 0, joins: 0/0} -foo [InlPrag=NOUSERINLINE[0]] :: (Int, Int) -> Int -> Int +foo [InlPrag=NOUSERINLINE[final]] :: (Int, Int) -> Int -> Int [GblId, Arity=2, Str=<S(SL),1*U(1*U(U),A)><S,1*U(U)>, @@ -56,24 +53,25 @@ foo [InlPrag=NOUSERINLINE[0]] :: (Int, Int) -> Int -> Int Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=2,unsat_ok=True,boring_ok=False) - Tmpl= \ (w_sHs [Occ=Once!] :: (Int, Int)) - (w1_sHt [Occ=Once!] :: Int) -> - case w_sHs of { (ww1_sHw [Occ=Once!], _ [Occ=Dead]) -> - case ww1_sHw of { GHC.Types.I# ww4_sHz [Occ=Once] -> - case w1_sHt of { GHC.Types.I# ww6_sHF [Occ=Once] -> - case Lib.$wfoo ww4_sHz ww6_sHF of ww7_sHJ [Occ=Once] { __DEFAULT -> - GHC.Types.I# ww7_sHJ + Tmpl= \ (w_sEf [Occ=Once1!] :: (Int, Int)) + (w1_sEg [Occ=Once1!] :: Int) -> + case w_sEf of { (ww1_sEj [Occ=Once1!], _ [Occ=Dead]) -> + case ww1_sEj of { GHC.Types.I# ww4_sEm [Occ=Once1] -> + case w1_sEg of { GHC.Types.I# ww6_sEs [Occ=Once1] -> + case Lib.$wfoo ww4_sEm ww6_sEs of ww7_sEw [Occ=Once1] + { __DEFAULT -> + GHC.Types.I# ww7_sEw } } } }}] foo - = \ (w_sHs :: (Int, Int)) (w1_sHt :: Int) -> - case w_sHs of { (ww1_sHw, ww2_sHB) -> - case ww1_sHw of { GHC.Types.I# ww4_sHz -> - case w1_sHt of { GHC.Types.I# ww6_sHF -> - case Lib.$wfoo ww4_sHz ww6_sHF of ww7_sHJ { __DEFAULT -> - GHC.Types.I# ww7_sHJ + = \ (w_sEf :: (Int, Int)) (w1_sEg :: Int) -> + case w_sEf of { (ww1_sEj, ww2_sEo) -> + case ww1_sEj of { GHC.Types.I# ww4_sEm -> + case w1_sEg of { GHC.Types.I# ww6_sEs -> + case Lib.$wfoo ww4_sEm ww6_sEs of ww7_sEw { __DEFAULT -> + GHC.Types.I# ww7_sEw } } } |