Note [Example of case-merging and caseRules]

GHC/Core/Opt/Simplify/Utils.hs:2544 compiler 1 ticket

The case-transformation rules are quite powerful. Here's a
subtle example from #22375.  We start with

  data T = A | B | ...
    deriving Eq

  f :: T -> String
  f x = if | x==A -> "one"
           | x==B -> "two"
           | ...

In Core after a bit of simplification we get:

    f x = case dataToTagLarge# x of a# { _DEFAULT ->
          case a# of
            _DEFAULT -> case dataToTagLarge# x of b# { _DEFAULT ->
                        case b# of
                           _DEFAULT -> ...
                           1# -> "two"
                        }
            0# -> "one"
          }

Now consider what mkCase does to these case expressions.
The case-merge transformation Note [Merge Nested Cases]
does this (affecting both pairs of cases):

    f x = case dataToTagLarge# x of a# {
             _DEFAULT -> case dataToTagLarge# x of b# {
                          _DEFAULT -> ...
                          1# -> "two"
                         }
             0# -> "one"
          }

Now Note [caseRules for dataToTag] does its work, again
on both dataToTagLarge# cases:

    f x = case x of x1 {
             _DEFAULT -> case dataToTagLarge# x1 of a# { _DEFAULT ->
                         case x of x2 {
                           _DEFAULT -> case dataToTagLarge# x2 of b# { _DEFAULT -> ... }
                           B -> "two"
                         }}
             A -> "one"
          }


The new dataToTagLarge# calls come from the "reconstruct scrutinee" part of
caseRules (note that a# and b# were not dead in the original program
before all this merging).  However, since a# and b# /are/ in fact dead
in the resulting program, we are left with redundant dataToTagLarge# calls.
But they are easily eliminated by doing caseRules again, in
the next Simplifier iteration, this time noticing that a# and b# are
dead.  Hence the "dead-binder" sub-case of Wrinkle 1 of Note
[Scrutinee Constant Folding] above.  Once we do this we get

    f x = case x of x1 {
             _DEFAULT -> case x1 of x2 { _DEFAULT ->
                         case x1 of x2 {
                            _DEFAULT -> case x2 of x3 { _DEFAULT -> ... }
                            B -> "two"
                         }}
             A -> "one"
          }

and now we can do case-merge again, getting the desired

    f x = case x of
            A -> "one"
            B -> "two"
            ...

References 2

Referenced by 3