PrimOpIds and PrimOpWrappers
I discussed with @bgamari two related issues
1. **Use the primop wrappers, instead of always eta-expanding.** The strange module `GHC.PrimopWrappers` is generated by `utils/genprimopcode` from `primops.txt.pp`. It contains bindings like
```
(+#) :: Int# -> Int# -> Int#
(+#) x y = (+#) x y
```
This defines a curried function `GHC.PrimopWrappers.(+#)`, whose implementation is an unboxed machine add. The code generator spots that saturated `(+#) x y` in the right hand side, and generates a machine add.
Why do we need these curried functions? So that in a higher order call like `f (+#)`, we can pass `GHC.PrimopWrappers.(+#)`.
An alternative, is to eta-expand, so that we have `f (\x y. (+#) x y)`; now we don't need that wrapper.
We *must* eta-expand for levity-polymorphic primops, because we can't compile levity-polymorphic code in `GHC.PrimopWrappers`. The `hasNoBinding` predicate is true for functions that have no binding -- and that must include levity-polymorphic primops.
In !6197 I tried making `hasNoBinding` return False for all non-levity-polymorphic primops. But that caused
```
ghci> data A
<interactive>: internal error: stg_ap_v_ret
```
This error comes from somewhere near this code in GHC.UI.Monad
```
runDecls' :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe [GHC.Name])
runDecls' decls = do
st <- getGHCiState
liftIO (print "hello2")
reifyGHCi $ \x ->
withProgName (progname st) $
withArgs (args st) $
reflectGHCi x $
GHC.handleSourceError
(\e -> do GHC.printException e;
return Nothing)
(Just <$> GHC.runParsedDecls decls)
```
If you comment out *both* the `withProgName` and `withArgs` calls, it works; if not, you crash.
I'm not sure why; @bgamari may try to find out.
2. **De-duplicate primop wrappers**. GHC currently builds two *different* Ids for PrimOps. In GHC.Types.Id.Make:
```
mkPrimOpId :: PrimOp -> Id
mkPrimOpId prim_op
```
In GHC.Builtin.PrimOps:
```
primOpWrapperId :: PrimOp -> Id
primOpWrapperId op = mkVanillaGlobalWithInfo name ty info
```
We put both into the symbol table.
We also currently generate (using `genprimopcode`) *two* modules:
* `GHC.Prim.hs` which contains accurate type signatures and Haddock docs; all RHS are bottom. Also `data Char#` etc (no RHS) for primitive types. This module is used only for Haddock to generate docs.
* `GHC.Primopwrappers.hs` which contains no Haddock, just wrappers. Used for unsaturated applications.
There seems no reason for all this duplication. Instead:
* Kill off `GHC.PrimopWrappers.hs`; instead generate **one** file, but with module name `GHC.Prim`, with accurate types, Haddock, and (for rep-mono primops) wrappers.
* This module is generated by `genprimopcode` from `primops.txt.pp`.
* It contains Haddock docs for the primops; this documentation comes form `primops.txt.pp`
* Even representation-polymorphic primops (for which a wrapper makes no sense) get a defn in `GHC.Prim`, solely to carry the Haddock documentation.
* Primitive types get `data Char#` with Haddock docs in `GHC.Prim`.
* Pseudo-ops like `nullAddr#` have a type and Haddock, but a dummy (bottom) RHS. They get compulsory unfoldings, so we will never call them.
* Kill off `primOpWrapperId`; use `primOpId` instead. (Kill `mkPrimOpWrapperUnique` too.)
Ben is going to look into this. Slightly fiddly, but makes things simpler; and the symbol
table will be smaller.
NB: three kinds of things are defined in `primops.txt.pp`:
* Primitive types. `genprimopcode` ignores them.
* Primops. `genprimopcode` generates a wrapper function.
* Pseudo-ops. `genprimopcode` ....
Things to watch out for: #18079, #19982
issue