Improve heap checks for primops, optimize tagToEnum# in Core

Summary:
We want to eliminate all calls to `tagToEnum#` at the Core level (#8317). This is possible thanks to new comparison primops added in GHC 7.8. Moreover, we want to have `isTrue#` and `isFalse#` function defined like this:

```haskell
isTrue# :: Int# -> Bool
isTrue# 1# = True
isTrue# _  = False

isFalse# :: Int# -> Bool
isFalse# 0# = True
isFalse# _  = False
```

The intention is that these functions can be used instead of `tagToEnum#`, for example like this:

```haskell
f :: Int# -> Int
f x | isTrue# (x ># 0#) = I# x
    | otherwise         = -(I# x)
```

If we compile the above code we get the following Core:

```haskell
A.f =
  \ (x_aqM :: GHC.Prim.Int#) ->
    case GHC.Prim.># x_aqM 0 of _ {
      __DEFAULT -> GHC.Types.I# (GHC.Prim.negateInt# x_aqM);
      1 -> GHC.Types.I# x_aqM
    }
```

Despite good Core the code generator produces bad Cmm because it pushes heap checks inside case alternatives, which results in unnecessarily large object code (see #8326).

This patch intends to fix both #8326 and #8317. #8317 was already fixed by Simon PJ but the fix was commented out until we fix #8326. This patch uncomments Simon's fix to #8317.

I believe that the fix for #8326 should be in the `cgCase` function in `codeGen/StgCmmExpr.hs`. This function decides whether the heap check should be placed inside case alternatives. Let's take a look at different equations for that function in the current HEAD (some equations omitted):

{{{
cgCase (StgOpApp (StgPrimOp op) args _) bndr (AlgAlt tycon) alts -- (1)
 | isEnumerationTyCon tycon

cgCase (StgApp v []) bndr alt_type@(PrimAlt _) alts -- (2)
  | isUnLiftedType (idType v) || reps_compatible

cgCase scrut bndr alt_type alts -- (3)
  = do {(...)
       ; let do_gc  | not simple_scrut = True
                    | isSingleton alts = False
                    | up_hp_usg > 0    = False
                    | otherwise        = True
               -- cf Note [Compiling case expressions]
             gc_plan = if do_gc then GcInAlts alt_regs else NoGcInAlts
}}}

Case (1) is the special case-on-bool. But this won't trigger on our generated core because the case alternatives are not algebraic TyCons (`AlgAlt tycon` pattern match). Case (2) compiles case expressions that have primitive (unboxed) alternatives but (2) won't trigger either because our scrutinee is a `StgOpApp`, not `StgApp`. This means our code will be compiled by the general case (3). This case uses `do_gc` to decide whether to place heap check in the case alternatives. With the current implementation our example Core code takes the `otherwise` branch and we end up with heap checks in case alternatives.

I see two ways of fixing this. One is to extend the general case by defining a new guard in `do_gc`. This guard would require a new function that recognizes that for some primops (like comparisons) we should not place heap checks in case alternatives. Second approach is to create a new case of `cgCase` that would compile applications of primops.

In my patch I have removed the special case for compiling `tagToEnum#` and created a new case for compiling primops with primitive alternatives:

```haskell
cgCase (StgOpApp (StgPrimOp op) args _) bndr alt_type@(PrimAlt _) alts
--  | isComparisonPrimOp op
  = do { dflags <- getDynFlags -- see Note [Case on primops]
       ; tmp <- newTemp (bWord dflags)
       ; cgPrimOp [tmp] op args
       ; emitAssign (CmmLocal (idToReg dflags (NonVoid bndr)))
                    (CmmReg (CmmLocal tmp))
       ; _ <- bindArgsToRegs [NonVoid bndr]
       ; cgAlts (NoGcInAlts,AssignedDirectly) (NonVoid bndr) alt_type alts }
```

The code shown above lead to a panic on `doWriteByteArrayOp` primop. Obviously, not all primops can be compiled that way. I tried to restrict the range of primops compiled that way by introducing `isComparisonPrimOp` function:

```
isComparisonPrimOp :: PrimOp -> Bool
isComparisonPrimOp op = case (primOpInfo op) of
                         Compare _ _ -> True
                         _           -> False
```

This is of course too conservative. For example bitwise logical operators like `and#` or `notI#` can also be compiled that way.

Now there are some decission to be made and I want to hear from others what you think about these:

  * We need to properly define a subset of primops that when scrutinized don't need heap checks in case alternatives. First of all how do I know which primops are these? Secondly, what is the best way of doing this? I think it would be best to add new field to primop description in `primops.txt.pp` and have `genprimopcode` program generate a file that would later be included in `prelude/PrimOp.lhs`.
  * Once we do the above perhaps we don't need the special case in `cgCase`? Perhaps we can just extend `do_gc` check in the general case? I am unable to tell that since I don't fully understand the code for the general case. Here I need help from someone more experienced.

Please note also that at the moment I am unable to run a proper validate on my machine due to breakage from 674c631ea111233daa929ef63500d75ba0db8858 so I'm not sure that my patch is correct. I've run the testuite using WAY=normal and things look good, except for T3772, which needs updating the expected output.

Test Plan:
1. validate using extra `-dcmm-lint` option
2. run nofib and look at the results. My expectation is that this patch should not impact performance in any way. It shouldn't also impact the size of compiled files. If any of these happens then something wrong might be going on in which case we need to investigate.
3. eyeball the generated Cmm as a sanity check

Since I don't have access to any powerful server I would appreciate if someone could do the nofib runs for me.

Reviewers: simonpj, simonmar, austin

Subscribers: thomie, simonmar, ezyang, carter

Differential Revision: https://phabricator.haskell.org/D343

GHC Trac Issues: #8326, #8317