... | ... | @@ -22,13 +22,16 @@ All Integer implementations should export the same set of types and functions fr |
|
|
## How Integer is handled inside GHC
|
|
|
|
|
|
|
|
|
Integers are represented using the `HsInteger` constructor of `HsLit` for the early phases of compilation (e.g. type checking), but for later stages, once we use the `Core` representation, they are converted to the `LitInteger` constructor of the `Literal` type by `mkIntegerExpr`. While `Integer`s aren't "machine literals" like the other `Literal` constructors, it is more convenient when writing rules to pretend that they are literals rather than having to understand their real core representation.
|
|
|
Integers are represented using the `HsInteger` constructor of `HsLit` for the early phases of compilation (e.g. type checking), but for later stages, once we use the `Core` representation, they are converted to the `LitInteger` constructor of the `Literal` type by `mkIntegerExpr`. While `Integer`s aren't "machine literals" like the other `Literal` constructors, it is more convenient when writing rules to pretend that they are literals rather than having to understand their real core representation. We also carry around a `Type`, representing the `Integer` type, in the constructor, as we need access to it in a few functions (e.g. `literalType`).
|
|
|
|
|
|
|
|
|
All of the types and functions in the `Integer` interface have built-in names, e.g. `plusIntegerName`, defined in [compiler/prelude/PrelNames.lhs](/trac/ghc/browser/ghc/compiler/prelude/PrelNames.lhs) and included in `basicKnownKeyNames`. This allows us to match on all of the functions in `builtinIntegerRules` in [compiler/prelude/PrelRules.lhs](/trac/ghc/browser/ghc/compiler/prelude/PrelRules.lhs), so we can constant-fold Integer expressions.
|
|
|
|
|
|
|
|
|
We keep the `LitInteger` representation as late as possible; in particular, it's important that this representation is used in unfoldings in interface files, so that constant folding can happen on expressions that get inlined. We only convert it to a proper core representation of Integer in [compiler/coreSyn/CorePrep.lhs](/trac/ghc/browser/ghc/compiler/coreSyn/CorePrep.lhs), where we normally use the Id for `mkInteger` (which we are carrying around in the `LitInteger` constructor) to build an expression like `mkInteger True [123, 456]` (where the `Bool` represents the sign, and the list of `Int`s are 31 bit chunks of the absolute value from lowest to highest).
|
|
|
We keep the `LitInteger` representation as late as possible; in particular, it's important that this representation is used in unfoldings in interface files, so that constant folding can happen on expressions that get inlined. We only convert it to a proper core representation of Integer in [compiler/coreSyn/CorePrep.lhs](/trac/ghc/browser/ghc/compiler/coreSyn/CorePrep.lhs), which looks up the Id for `mkInteger` and uses it to build an expression like `mkInteger True [123, 456]` (where the `Bool` represents the sign, and the list of `Int`s are 31 bit chunks of the absolute value from lowest to highest).
|
|
|
|
|
|
|
|
|
However, there is a special case for `Integer`s that are within the range of `Int` when the `integer-gmp` implementation is being used; in that case, we use the `S#` constructor (via `integerGmpSDataCon` in [compiler/prelude/TysWiredIn.lhs](/trac/ghc/browser/ghc/compiler/prelude/TysWiredIn.lhs)) to break teh abstraction and directly create the datastructure. |
|
|
However, there is a special case for `Integer`s that are within the range of `Int` when the `integer-gmp` implementation is being used; in that case, we use the `S#` constructor (via `integerGmpSDataCon` in [compiler/prelude/TysWiredIn.lhs](/trac/ghc/browser/ghc/compiler/prelude/TysWiredIn.lhs)) to break the abstraction and directly create the datastructure.
|
|
|
|
|
|
|
|
|
Most of the functions in the Integer implementation are marked `NOINLINE`. This is because inlining them is generally not beneficial (any constant folding is already handled by the built-in rules), and in fact can be harmful: In the GMP representation, each argument can be one of two constructors (`S#` and `J#`), which leads to 2 branches. When you have a number of `Integer` arithmetic operations, you can get an exponential code explosion if they all get inlined. |