#5539: GHC panic -  Simplifier ticks exhausted
---------------------------------+------------------------------------------
  Reporter:  hvr                 |          Owner:  simonpj       
      Type:  bug                 |         Status:  new           
  Priority:  high                |      Milestone:  7.4.1         
 Component:  Compiler            |        Version:  7.3           
Resolution:                      |       Keywords:                
        Os:  Linux               |   Architecture:  x86_64 (amd64)
   Failure:  Compile-time crash  |     Difficulty:  Unknown       
  Testcase:                      |      Blockedby:                
  Blocking:                      |        Related:                
---------------------------------+------------------------------------------
Changes (by simonpj):

 * cc: rl (added)


Comment:

 I have gotten as far as compiling `vector-algorithms`, and indeed I get
 {{{
 [8 of 9] Compiling Data.Vector.Algorithms.Intro (
 Data/Vector/Algorithms/Intro.hs, dist/build/Data/Vector/Algorithms/Intro.o
 )
 ghc: panic! (the 'impossible' happened)
   (GHC version 7.3.20111030 for x86_64-unknown-linux):
         Simplifier ticks exhausted
     When trying UnfoldingDone ghc-prim:GHC.Classes.not{v r1d} [gid]
     To increase the limit, use -fsimpl-tick-factor=N (default 100)
     If you need to do this, let GHC HQ know, and what factor you needed
     To see detailed counts use -ddump-simpl-stats
     Total ticks: 42922
 }}}
 So what is going on?  To take one example, there's a call of
 `Data.Vector.Algorithms.Optimal.sort3ByIndex`, and that inlines a giant
 function.  Why giant?  Well, `sort3ByIndex` has three calls of
 {{{
 UNSAFE_CHECK(checkIndex) "sort3ByIndex" i (length a)
 }}}
 Moreover, `sort3ByIndex` calls the INLINE function
 `Data.Vector.Generic.Mutable.unsafeRead` 3 times, and `unsafeWrite` 12
 times.  Each of those functions has another use of `UNSAFE_CHECK`.  This
 UNSAFE_CHECK thing is a CPP macro which expands thus
 {{{
 UNSAFE_CHECK(checkIndex) "sort3ByIndex" i (length a) x

 --> (by cpp)
 checkIndex "Foo.hs" 45 Unsafe "sort3ByIndex" i (length a) x

 --> (INLINE checkIndex)
 let n = length a in
 check "Foo.hs" 45 Unsafe "sort3ByIndex" (checkIndex_msg i n) (i >= 0 && i
 < n) x

 --> (INLINE check)
 let n = length a in
 if (not (doChecks Unsafe) || (i >= 0 && i < n))
 then x
 else error "Foo.hs" 45 Unsafe "sort3ByIndex" (checkIndex_msg i n)
 }}}
 Now imagine all of that inlined 18 times, and you get a lot of code.  And
 that's only `sort3ByIndex`, which itself has an INLINE pragma.

 Let's just focus on the number of calls to `(||)`.  In the module
 `Intro.hs`:
  * `sortByBounds` calls `sort2ByOffset`, `sort3ByOffset`, and
 `sort4ByOffset` (and `introsort` which I'll temporarily ignore)
  * Those three calls are inlined, resulting in 110 calls to `(||)`.
  * But `sortByBounds` is itself an INLINE function, and is inlined into
 `sortBy`; result = 110 more calls to `(||)`.
  * And `sortBy` is INLINE, and is inlined into `sort`, giving another 110
 calls; total so far 330 calls.
  * Along with those 330 calls to `(||)` are 330 calls to `not`.  All those
 are finally inlined independently and simplified away, but it uses up
 ticks!
  * Moreover all these `sort3ByIndex` functions work in an arbitrary monad,
 so it's all stitched together will calls to the overloaded `(>>)` and
 dictionary-passing.
 And I did all this measurement with `Intro.introsort` commented out; it
 does more crazy stuff. I think this is why the code is so bloated.

 Now, in fact `vector` is compiled in such a way that `(doChecks Unsafe)`
 evaluates to `False`.  So in the bloated unfolding for `UNSAFE_CHECK` we
 see this:
 {{{
 let n = length a in
 case (not False || (i >= 0 && i < n)) of
   True  -> a
   False -> error "Foo.hs" 45 Unsafe "sort3ByIndex" (checkIndex_msg i n)
 }}}
 Look at that `(not False)`!  If GHC had been clever enough to inline `not`
 and `||` in the unfolding of `sort3ByIndex`, all this code would have
 collapsed away as dead code -- and indeed it does so in the eventual
 client module.

 It's hard for GHC to know how clever to be.
  * The basic idea of an INLINE pragma on a definition `f x = <expr>`, then
 we'll inline precisely `<expr>` at every call site. GHC is faithfully
 doing this.
  * However GHC does ''some'' gentle simplification on `<expr>` before
 stowing it away ready for inlining:
    * It does simple case-of-constructor stuff
    * It inlines functions that are themselves marked INLINE, or calls that
 use the `inline` pseudo-function.

 The current defn of `Data.Vector.Internal.check` is
 {{{
 check file line kind loc msg cond x
   | not (doChecks kind) || cond = x
   | otherwise = error file line kind loc msg
 }}}
 Here are two ways of making the `not` and `(||)` inline even inside
 `check`'s inlining. First, do it by hand:
 {{{
 check file line kind loc msg cond x
   = case doChecks kind of
        False            -> x
        True | cond      -> x
             | otherwise -> error file line kind loc msg
 }}}
 Second, use `inline`:
 {{{
 check file line kind loc msg cond x
   | inline (||) (inline not (doChecks kind)) cond = x
   | otherwise = error file line kind loc msg
 }}}
 Then the size of `Intro` is more reasonable, and compiles within the
 current tick bounds without problem.

 I have taken the trouble to write this up so that everyone gets a clearer
 idea of how inlining works.

 I will make the above change to `check` in package `vector` (at least in
 GHC's tree). '''BUT if you change the macros so that full bounds-checking
 is on, all the bloat will return'''.  So that really needs attention from
 Roman. For example, when bounds checking is on, the indexing fuctions
 should probably not inline.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5539#comment:28>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to