PrimOpIds and PrimOpWrappers
I discussed with @bgamari two related issues
-
Use the primop wrappers, instead of always eta-expanding. The strange module
GHC.PrimopWrappers
is generated byutils/genprimopcode
fromprimops.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 passGHC.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
. ThehasNoBinding
predicate is true for functions that have no binding -- and that must include levity-polymorphic primops.In !6197 (closed) I tried making
hasNoBinding
return False for all non-levity-polymorphic primops. But that causedghci> 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
andwithArgs
calls, it works; if not, you crash.I'm not sure why; @bgamari may try to find out.
-
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. Alsodata 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 nameGHC.Prim
, with accurate types, Haddock, and (for rep-mono primops) wrappers.- This module is generated by
genprimopcode
fromprimops.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 inGHC.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.
- This module is generated by
-
Kill off
primOpWrapperId
; useprimOpId
instead. (KillmkPrimOpWrapperUnique
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 (closed), #19982