Note [RuntimeRep and PrimRep]
This Note describes the relationship between GHC.Types.RuntimeRep
(of levity/representation polymorphism fame) and GHC.Core.TyCon.PrimRep,
as these types are closely related.
A "primitive entity" is one that can be
* stored in one register
* manipulated with one machine instruction
Examples include:
* a 32-bit integer
* a 32-bit float
* a 64-bit float
* a machine address (heap pointer), etc.
* a quad-float (on a machine with SIMD register and instructions)
* ...etc...
The "representation or a primitive entity" specifies what kind of register is
needed and how many bits are required. The data type GHC.Core.TyCon.PrimRep
enumerates all the possibilities.
data PrimRep
= LiftedRep -- ^ Lifted pointer
| UnliftedRep -- ^ Unlifted pointer
| Int8Rep -- ^ Signed, 8-bit value
| Int16Rep -- ^ Signed, 16-bit value
...etc...
| VecRep Int PrimElemRep -- ^ SIMD fixed-width vector
The Haskell source language is a bit more flexible: a single value may need multiple PrimReps.
For example
utup :: (# Int, Int #) -> Bool
utup x = ...
Here x :: (# Int, Int #), and that takes two registers, and two instructions to move around.
Unboxed sums are similar.
Every Haskell expression e has a type ty, whose kind is of form TYPE rep
e :: ty :: TYPE rep
where rep :: RuntimeRep. Here rep describes the runtime representation for e's value,
but RuntimeRep has some extra cases:
data RuntimeRep = VecRep VecCount VecElem -- ^ a SIMD vector type
| TupleRep [RuntimeRep] -- ^ An unboxed tuple of the given reps
| SumRep [RuntimeRep] -- ^ An unboxed sum of the given reps
| BoxedRep Levity -- ^ boxed; represented by a pointer
| IntRep -- ^ signed, word-sized value
...etc...
data Levity = Lifted
| Unlifted
It's all in 1-1 correspondence with PrimRep except for TupleRep and SumRep,
which describe unboxed products and sums respectively. RuntimeRep is defined
in the library ghc-prim:GHC.Types. It is also "wired-in" to GHC: see
GHC.Builtin.Types.runtimeRepTyCon. The unarisation pass, in GHC.Stg.Unarise, transforms the
program, so that every variable has a type that has a PrimRep. For
example, unarisation transforms our utup function above, to take two Int
arguments instead of one (# Int, Int #) argument.
Also, note that boxed types are represented slightly differently in RuntimeRep
and PrimRep. PrimRep just has the nullary LiftedRep and UnliftedRep data
constructors. RuntimeRep has a BoxedRep data constructor, which accepts a
Levity. The subtle distinction is that since BoxedRep can accept a variable
argument, RuntimeRep can talk about levity polymorphic types. PrimRep, by
contrast, cannot.
See also Note [Getting from RuntimeRep to PrimRep] and Note [VoidRep]. References 2
- Getting from RuntimeRep to PrimRep GHC.Types.RepType
- VoidRep GHC.Types.RepType
Referenced by 6
- GHC.Types.RepType call site ×2
- rep swamp GHC.Core.TyCon
- GHC.Core.TyCon call site
- VoidRep GHC.Types.RepType
- Getting from RuntimeRep to PrimRep GHC.Types.RepType