Note [Scrutinee Constant Folding]

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

     case x op# k# of _ {  ===> case x of _ {
        a1# -> e1                  (a1# inv_op# k#) -> e1
        a2# -> e2                  (a2# inv_op# k#) -> e2
        ...                        ...
        DEFAULT -> ed              DEFAULT -> ed

     where (x op# k#) inv_op# k# == x

And similarly for commuted arguments and for some unary operations.

The purpose of this transformation is not only to avoid an arithmetic
operation at runtime but to allow other transformations to apply in cascade.

Example with the "Merge Nested Cases" optimization (from #12877):

      main = case t of t0
         0##     -> ...
         DEFAULT -> case t0 `minusWord#` 1## of t1
            0##     -> ...
            DEFAULT -> case t1 `minusWord#` 1## of t2
               0##     -> ...
               DEFAULT -> case t2 `minusWord#` 1## of _
                  0##     -> ...
                  DEFAULT -> ...

  becomes:

      main = case t of _
      0##     -> ...
      1##     -> ...
      2##     -> ...
      3##     -> ...
      DEFAULT -> ...

There are some wrinkles.

Wrinkle 1:
  Do not apply caseRules if there is just a single DEFAULT alternative,
  unless the case-binder is dead. Example:
     case e +# 3# of b { DEFAULT -> rhs }
  If we applied the transformation here we would (stupidly) get
     case e of b' { DEFAULT -> let b = b' +# 3# in rhs }
  and now the process may repeat, because that let will really
  be a case. But if the original case binder b is dead, we instead get
     case e of b' { DEFAULT -> rhs }
  and there is no such problem.

  See Note [Example of case-merging and caseRules] for a compelling
  example of why this dead-binder business can be really important.


Wrinkle 2:
  The type of the scrutinee might change.  E.g.
        case tagToEnum (x :: Int#) of (b::Bool)
          False -> e1
          True -> e2
  ==>
        case x of (b'::Int#)
          DEFAULT -> e1
          1#      -> e2

Wrinkle 3:
  The case binder may be used in the right hand sides, so we need
  to make a local binding for it, if it is alive.  e.g.
         case e +# 10# of b
           DEFAULT -> blah...b...
           44#     -> blah2...b...
  ===>
         case e of b'
           DEFAULT -> let b = b' +# 10# in blah...b...
           34#     -> let b = 44# in blah2...b...

  Note that in the non-DEFAULT cases we know what to bind 'b' to,
  whereas in the DEFAULT case we must reconstruct the original value.
  But NB: we use b'; we do not duplicate 'e'.

Wrinkle 4:
  In dataToTag we might need to make up some fake binders;
  see Note [caseRules for dataToTag] in GHC.Core.Opt.ConstantFold

References 2

Referenced by 3