Cure exponential behaviour in the simplifier
authorSimon Peyton Jones <simonpj@microsoft.com>
Wed, 26 Apr 2017 16:31:36 +0000 (17:31 +0100)
committerSimon Peyton Jones <simonpj@microsoft.com>
Fri, 28 Apr 2017 08:55:07 +0000 (09:55 +0100)
commita1b753e8b1475659440f524b3e66dfbea31c5787
tree5263d0b32fd2d637b4678edeb7c7598e097abb04
parent25754c83c9be3bf843310b1c7877c42fa3f9f3c7
Cure exponential behaviour in the simplifier

This patch nails a Bad Bug exposed in Trac #13379. Roughly,
a deeply-nested application like
   f (f (f ....) ) )
could make the simplifier go exponential -- without producing
an exponential-sized result!

The reason was that we
  - simplified a (big) function argument
  - then decided to inline the function
  - then preInilneUnconditionally the argument
  - and then re-simplified the big argument

And if the "big argument" itself had a similar structure
things could get very bad.

Once I'd understood, it was easy to fix:

* See Note Note [Avoiding exponential behaviour] for an overview

* The key change is that Simplify.simplLam now as a case for
  (isSimplified dup). This is what removes the perf bug.

* But I also made simplCast more parsimonious about simplifying,
  avoiding doing so when the coercion is Refl

* And similarly I now try to avoid simplifying arguments
  where possible before applying rules.
  See Note [Trying rewrite rules]

The latter two points tackle common cases, and in those cases make the
simplifier take fewer iterations.
compiler/simplCore/SimplUtils.hs
compiler/simplCore/Simplify.hs
testsuite/tests/perf/compiler/T13379.hs [new file with mode: 0644]
testsuite/tests/perf/compiler/T4007.stdout
testsuite/tests/perf/compiler/all.T
testsuite/tests/simplCore/should_compile/T3234.stderr