#7360: Case-of-identical-alts optimisation fails abjectly
---------------------------------+------------------------------------------
    Reporter:  simonpj           |       Owner:                  
        Type:  bug               |      Status:  new             
    Priority:  normal            |   Milestone:                  
   Component:  Compiler          |     Version:  7.6.1           
    Keywords:                    |          Os:  Unknown/Multiple
Architecture:  Unknown/Multiple  |     Failure:  None/Unknown    
  Difficulty:  Unknown           |    Testcase:                  
   Blockedby:                    |    Blocking:                  
     Related:                    |  
---------------------------------+------------------------------------------
 Herbert Valerio Riedel writes: I've been trying to improve/fix a minor
 optimization sub-optimality w.r.t to the following code (code like that
 results from the generics-based NFData deriver[1]):
 {{{
     data Foo = Foo1 | Foo2 | Foo3 !Int

     rnf1 :: Foo -> ()
     rnf1 x = case x of
                Foo1 -> ()
                Foo2 -> ()
                Foo3 {} -> ()
 }}}
 which the current GHC 7.6.1 translates to the following core
 expression:
 {{{
     NFDataTest2.rnf1 =
       \ x_aeG ->
         case x_aeG of _ {
           __DEFAULT -> GHC.Tuple.();
           NFDataTest2.Foo3 ds_deT -> GHC.Tuple.()
         }
 }}}
 ...whereas I'd have expected it to to compile it to a collapsed
 `__DEFAULT`-only case, i.e.
 {{{
     NFDataTest2.rnf1 =
       \ x_aeG -> case x_aeG of _ { __DEFAULT -> GHC.Tuple.() }
 }}}
 Now I've been hunting it down to the function `SimplUtils.mkCase1` [2],
 which according to the source-code comments, is supposed to merge
 identical alternatives, i.e.:
 {{{
 | 3.  Merge identical alternatives.
 |     If several alternatives are identical, merge them into
 |     a single DEFAULT alternative.  I've occasionally seen this
 |     making a big difference:
 |
 |         case e of               =====>     case e of
 |           C _ -> f x                         D v -> ....v....
 |           D v -> ....v....                   DEFAULT -> f x
 |           DEFAULT -> f x
 }}}
 ...and the `mkCase1` function itself reads as follows:
 {{{
     mkCase1 dflags scrut case_bndr alts_ty ((_con1,bndrs1,rhs1) :
 con_alts)
       | all isDeadBinder bndrs1                     -- Remember the
 default
       , length filtered_alts < length con_alts      -- alternative comes
 first
             -- Also Note [Dead binders]
       = do  { tick (AltMerge case_bndr)
             ; mkCase2 dflags scrut case_bndr alts_ty alts' }
       where
         alts' = (DEFAULT, [], rhs1) : filtered_alts
         filtered_alts         = filter keep con_alts
         keep (_con,bndrs,rhs) = not (all isDeadBinder bndrs && rhs
 `cheapEqExpr` rhs1)
 }}}
 Now the problem seems to be, that `isDeadBinder` returns `False`; so I
 hacked up `mkCase1` and inserted a `occurAnalyseExpr` on artificially
 constructed single-alternative 'Case' values before applying
 `isDeadBinder`, and then it would return `True` and simplify the case
 expression as expected.

 So now my question is, why isn't the occurrence information available for
 the case-alternative's binders (the occInfo is set to `NoOccInfo`) at
 `mkCase1`-time?  When is occurence analysis performed relative to the
 simplifier?


  * [1]: [http://hackage.haskell.org/package/deepseq-generics]
  * [2]:
 
[http://www.haskell.org/ghc/docs/7.6.1/html/libraries/ghc-7.6.1/src/SimplUtils.html#mkCase1]

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

_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to