Skip to content

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information