STG CSE makes dead binders undead
Consider the following example:
go :: (a -> b) -> Either String a -> Either String b
go f (Right a) = Right (f a)
go _ (Left e) = Left e
GHC with -O2
converts it into the following STG:
TestUndead.go
:: forall a b.
(a -> b)
-> Data.Either.Either GHC.Base.String a
-> Data.Either.Either GHC.Base.String b
[GblId,
Arity=2,
Caf=NoCafRefs,
Str=<L,1*C1(U)><S,1*U>,
Unf=OtherCon []] =
\r [f_s17n ds_s17o]
case ds_s17o of {
Data.Either.Left e_s17q [Occ=Once] -> wild_s17p;
Data.Either.Right a1_s17r [Occ=Once] ->
let {
sat_s17s [Occ=Once] :: b_aVN
[LclId] =
\u [] f_s17n a1_s17r;
} in Data.Either.Right [sat_s17s];
};
Notice that the dead binder wild_s17p
is now alive (in the first alternative) but it isn't shown in case ds_s17o of {
because the pretty-printer still assumes it is dead.
I think that in stgCseExpr .. (StgCase ...)
(simplStg/StgCse.hs) we should check if the new binder is alive in the new alternatives, just like we do in coreToStgExpr (Case ...)
(stgSyn/CoreToStg.hs), and use setIdOccInfo (ManyOccs NoTailCallInfo)
on the new binder if necessary.
Trac metadata
Trac field | Value |
---|---|
Version | 8.2.2 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |