Case-of-identical-alts optimisation fails abjectly
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
mkCase1function 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
Trac metadata
| Trac field | Value |
|---|---|
| Version | 7.6.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | hvr@gnu.org |
| Operating system | |
| Architecture |