Commit fc2ff6dd authored by Joachim Breitner's avatar Joachim Breitner Committed by Krzysztof Gogolewski

Make GHC (the library) flexible in the choice of integer library

Summary:
We have more and more users of GHC as a library, for example the
Haskell-to-WebAssembly-compiler https://github.com/tweag/asterius.
These need to make different decisions about various aspects of
code generation than the host compiler, and ideally GHC-the-library
allows them to set the `DynFlags` as needed.

This patch adds a new `DynFlag` that configures which `integer`
library to use. This flag is initialized by `cIntegerLibraryType`
(as before), and is only used in `CorePrep` to decide whether to
use `S#` or not.

The other code paths that were varying based on `cIntegerLibraryType`
are no now longer varying: The trick is to use `integer-wired-in`
as the `-this-unit-id` when compiling either `integer-gmp` or
`integer-simple`.

Test Plan: Validate is happy.

Reviewers: hvr, bgamari

Reviewed By: bgamari

Subscribers: TerrorJack, adamse, simonpj, rwbarton, carter

GHC Trac Issues: #13477

Differential Revision: https://phabricator.haskell.org/D5079
parent 3dedffa2
......@@ -137,7 +137,6 @@ module Module
import GhcPrelude
import Config
import Outputable
import Unique
import UniqFM
......@@ -1042,36 +1041,45 @@ parseModSubst = Parse.between (Parse.char '[') (Parse.char ']')
return (k, v)
-- -----------------------------------------------------------------------------
-- $wired_in_packages
-- Certain packages are known to the compiler, in that we know about certain
-- entities that reside in these packages, and the compiler needs to
-- declare static Modules and Names that refer to these packages. Hence
-- the wired-in packages can't include version numbers, since we don't want
-- to bake the version numbers of these packages into GHC.
--
-- So here's the plan. Wired-in packages are still versioned as
-- normal in the packages database, and you can still have multiple
-- versions of them installed. However, for each invocation of GHC,
-- only a single instance of each wired-in package will be recognised
-- (the desired one is selected via @-package@\/@-hide-package@), and GHC
-- will use the unversioned 'UnitId' below when referring to it,
-- including in .hi files and object file symbols. Unselected
-- versions of wired-in packages will be ignored, as will any other
-- package that depends directly or indirectly on it (much as if you
-- had used @-ignore-package@).
-- Make sure you change 'Packages.findWiredInPackages' if you add an entry here
{-
Note [Wired-in packages]
~~~~~~~~~~~~~~~~~~~~~~~~
Certain packages are known to the compiler, in that we know about certain
entities that reside in these packages, and the compiler needs to
declare static Modules and Names that refer to these packages. Hence
the wired-in packages can't include version numbers in their package UnitId,
since we don't want to bake the version numbers of these packages into GHC.
So here's the plan. Wired-in packages are still versioned as
normal in the packages database, and you can still have multiple
versions of them installed. To the user, everything looks normal.
However, for each invocation of GHC, only a single instance of each wired-in
package will be recognised (the desired one is selected via
@-package@\/@-hide-package@), and GHC will internall pretend that it has the
*unversioned* 'UnitId', including in .hi files and object file symbols.
Unselected versions of wired-in packages will be ignored, as will any other
package that depends directly or indirectly on it (much as if you
had used @-ignore-package@).
The affected packages are compiled with, e.g., @-this-unit-id base@, so that
the symbols in the object files have the unversioned unit id in their name.
Make sure you change 'Packages.findWiredInPackages' if you add an entry here.
For `integer-gmp`/`integer-simple` we also change the base name to
`integer-wired-in`, but this is fundamentally no different.
See Note [The integer library] in PrelNames.
-}
integerUnitId, primUnitId,
baseUnitId, rtsUnitId,
thUnitId, mainUnitId, thisGhcUnitId, interactiveUnitId :: UnitId
primUnitId = fsToUnitId (fsLit "ghc-prim")
integerUnitId = fsToUnitId (fsLit n)
where
n = case cIntegerLibraryType of
IntegerGMP -> "integer-gmp"
IntegerSimple -> "integer-simple"
integerUnitId = fsToUnitId (fsLit "integer-wired-in")
-- See Note [The integer library] in PrelNames
baseUnitId = fsToUnitId (fsLit "base")
rtsUnitId = fsToUnitId (fsLit "rts")
thUnitId = fsToUnitId (fsLit "template-haskell")
......
......@@ -1537,14 +1537,15 @@ lookupMkNaturalName dflags hsc_env
= guardNaturalUse dflags $ liftM tyThingId $
lookupGlobal hsc_env mkNaturalName
-- See Note [The integer library] in PrelNames
lookupIntegerSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)
lookupIntegerSDataConName dflags hsc_env = case cIntegerLibraryType of
lookupIntegerSDataConName dflags hsc_env = case integerLibrary dflags of
IntegerGMP -> guardIntegerUse dflags $ liftM (Just . tyThingDataCon) $
lookupGlobal hsc_env integerSDataConName
IntegerSimple -> return Nothing
lookupNaturalSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)
lookupNaturalSDataConName dflags hsc_env = case cIntegerLibraryType of
lookupNaturalSDataConName dflags hsc_env = case integerLibrary dflags of
IntegerGMP -> guardNaturalUse dflags $ liftM (Just . tyThingDataCon) $
lookupGlobal hsc_env naturalSDataConName
IntegerSimple -> return Nothing
......
......@@ -84,8 +84,6 @@ compiler/stage%/build/Config.hs : mk/config.mk mk/project.mk | $$(dir $$@)/.
@echo 'cBooterVersion = "$(GhcVersion)"' >> $@
@echo 'cStage :: String' >> $@
@echo 'cStage = show (STAGE :: Int)' >> $@
@echo 'cIntegerLibrary :: String' >> $@
@echo 'cIntegerLibrary = "$(INTEGER_LIBRARY)"' >> $@
@echo 'cIntegerLibraryType :: IntegerLibrary' >> $@
ifeq "$(INTEGER_LIBRARY)" "integer-gmp"
@echo 'cIntegerLibraryType = IntegerGMP' >> $@
......
......@@ -850,6 +850,9 @@ data DynFlags = DynFlags {
ghcLink :: GhcLink,
hscTarget :: HscTarget,
settings :: Settings,
integerLibrary :: IntegerLibrary,
-- ^ IntegerGMP or IntegerSimple. Set at configure time, but may be overriden
-- by GHC-API users. See Note [The integer library] in PrelNames
llvmTargets :: LlvmTargets,
llvmPasses :: LlvmPasses,
verbosity :: Int, -- ^ Verbosity level: see Note [Verbosity levels]
......@@ -1755,6 +1758,7 @@ defaultDynFlags mySettings (myLlvmTargets, myLlvmPasses) =
ghcMode = CompManager,
ghcLink = LinkBinary,
hscTarget = defaultHscTarget (sTargetPlatform mySettings),
integerLibrary = cIntegerLibraryType,
verbosity = 0,
optLevel = 0,
debugLevel = 0,
......
......@@ -953,12 +953,15 @@ pprTrustFlag flag = case flag of
-- -----------------------------------------------------------------------------
-- Wired-in packages
--
-- See Note [Wired-in packages] in Module
wired_in_pkgids :: [String]
wired_in_pkgids = map unitIdString wiredInUnitIds
type WiredInUnitId = String
type WiredPackagesMap = Map WiredUnitId WiredUnitId
wired_in_pkgids :: [WiredInUnitId]
wired_in_pkgids = map unitIdString wiredInUnitIds
findWiredInPackages
:: DynFlags
-> PackagePrecedenceIndex
......@@ -969,12 +972,15 @@ findWiredInPackages
WiredPackagesMap) -- map from unit id to wired identity
findWiredInPackages dflags prec_map pkgs vis_map = do
--
-- Now we must find our wired-in packages, and rename them to
-- their canonical names (eg. base-1.0 ==> base).
--
-- their canonical names (eg. base-1.0 ==> base), as described
-- in Note [Wired-in packages] in Module
let
matches :: PackageConfig -> String -> Bool
matches :: PackageConfig -> WiredInUnitId -> Bool
pc `matches` pid
-- See Note [The integer library] in PrelNames
| pid == unitIdString integerUnitId
= packageNameString pc `elem` ["integer-gmp", "integer-simple"]
pc `matches` pid = packageNameString pc == pid
-- find which package corresponds to each wired-in package
......@@ -994,8 +1000,8 @@ findWiredInPackages dflags prec_map pkgs vis_map = do
-- this works even when there is no exposed wired in package
-- available.
--
findWiredInPackage :: [PackageConfig] -> String
-> IO (Maybe PackageConfig)
findWiredInPackage :: [PackageConfig] -> WiredInUnitId
-> IO (Maybe (WiredInUnitId, PackageConfig))
findWiredInPackage pkgs wired_pkg =
let all_ps = [ p | p <- pkgs, p `matches` wired_pkg ]
all_exposed_ps =
......@@ -1014,20 +1020,19 @@ findWiredInPackages dflags prec_map pkgs vis_map = do
<> text " not found."
return Nothing
pick :: PackageConfig
-> IO (Maybe PackageConfig)
-> IO (Maybe (WiredInUnitId, PackageConfig))
pick pkg = do
debugTraceMsg dflags 2 $
text "wired-in package "
<> text wired_pkg
<> text " mapped to "
<> ppr (unitId pkg)
return (Just pkg)
return (Just (wired_pkg, pkg))
mb_wired_in_pkgs <- mapM (findWiredInPackage pkgs) wired_in_pkgids
let
wired_in_pkgs = catMaybes mb_wired_in_pkgs
wired_in_ids = mapMaybe definitePackageConfigId wired_in_pkgs
-- this is old: we used to assume that if there were
-- multiple versions of wired-in packages installed that
......@@ -1043,18 +1048,17 @@ findWiredInPackages dflags prec_map pkgs vis_map = do
-}
wiredInMap :: Map WiredUnitId WiredUnitId
wiredInMap = foldl' add_mapping Map.empty pkgs
where add_mapping m pkg
| Just key <- definitePackageConfigId pkg
, key `elem` wired_in_ids
= Map.insert key (DefUnitId (stringToInstalledUnitId (packageNameString pkg))) m
| otherwise = m
wiredInMap = Map.fromList
[ (key, DefUnitId (stringToInstalledUnitId wiredInUnitId))
| (wiredInUnitId, pkg) <- wired_in_pkgs
, Just key <- pure $ definitePackageConfigId pkg
]
updateWiredInDependencies pkgs = map (upd_deps . upd_pkg) pkgs
where upd_pkg pkg
| Just def_uid <- definitePackageConfigId pkg
, def_uid `elem` wired_in_ids
= let PackageName fs = packageName pkg
, Just wiredInUnitId <- Map.lookup def_uid wiredInMap
= let fs = installedUnitIdFS (unDefUnitId wiredInUnitId)
in pkg {
unitId = fsToInstalledUnitId fs,
componentId = ComponentId fs
......@@ -1074,7 +1078,9 @@ findWiredInPackages dflags prec_map pkgs vis_map = do
-- Helper functions for rewiring Module and UnitId. These
-- rewrite UnitIds of modules in wired-in packages to the form known to the
-- compiler. For instance, base-4.9.0.0 will be rewritten to just base, to match
-- compiler, as described in Note [Wired-in packages] in Module.
--
-- For instance, base-4.9.0.0 will be rewritten to just base, to match
-- what appears in PrelNames.
upd_wired_in_mod :: WiredPackagesMap -> Module -> Module
......
......@@ -110,6 +110,36 @@ by the user. For those things that *can* appear in source programs,
original-name cache.
See also Note [Built-in syntax and the OrigNameCache]
Note [The integer library]
~~~~~~~~~~~~~~~~~~~~~~~~~~
Clearly, we need to know the names of various definitions of the integer
library, e.g. the type itself, `mkInteger` etc. But there are two possible
implementations of the integer library:
* integer-gmp (fast, but uses libgmp, which may not be available on all
targets and is GPL licensed)
* integer-simple (slow, but pure Haskell and BSD-licensed)
We want the compiler to work with either one. The way we achieve this is:
* When compiling the integer-{gmp,simple} library, we pass
-this-unit-id integer-wired-in
to GHC (see the cabal file libraries/integer-{gmp,simple}.
* This way, GHC can use just this UnitID (see Module.integerUnitId) when
generating code, and the linker will succeed.
Unfortuately, the abstraction is not complete: When using integer-gmp, we
really want to use the S# constructor directly. This is controlled by
the `integerLibrary` field of `DynFlags`: If it is IntegerGMP, we use
this constructor directly (see CorePrep.lookupIntegerSDataConName)
When GHC reads the package data base, it (internally only) pretends it has UnitId
`integer-wired-in` instead of the actual UnitId (which includes the version
number); just like for `base` and other packages, as described in
Note [Wired-in packages] in Module. This is done in Packages.findWiredInPackages.
-}
{-# LANGUAGE CPP #-}
......@@ -136,8 +166,6 @@ import Unique
import Name
import SrcLoc
import FastString
import Config ( cIntegerLibraryType, IntegerLibrary(..) )
import Panic ( panic )
{-
************************************************************************
......@@ -355,6 +383,7 @@ basicKnownKeyNames
gcdIntegerName, lcmIntegerName,
andIntegerName, orIntegerName, xorIntegerName, complementIntegerName,
shiftLIntegerName, shiftRIntegerName, bitIntegerName,
integerSDataConName,naturalSDataConName,
-- Natural
naturalTyConName,
......@@ -433,9 +462,7 @@ basicKnownKeyNames
, typeErrorVAppendDataConName
, typeErrorShowTypeDataConName
] ++ case cIntegerLibraryType of
IntegerGMP -> [integerSDataConName,naturalSDataConName]
IntegerSimple -> []
]
genericTyConNames :: [Name]
genericTyConNames = [
......@@ -1118,11 +1145,8 @@ integerTyConName, mkIntegerName, integerSDataConName,
gcdIntegerName, lcmIntegerName,
andIntegerName, orIntegerName, xorIntegerName, complementIntegerName,
shiftLIntegerName, shiftRIntegerName, bitIntegerName :: Name
integerTyConName = tcQual gHC_INTEGER_TYPE (fsLit "Integer") integerTyConKey
integerSDataConName = dcQual gHC_INTEGER_TYPE (fsLit n) integerSDataConKey
where n = case cIntegerLibraryType of
IntegerGMP -> "S#"
IntegerSimple -> panic "integerSDataConName evaluated for integer-simple"
integerTyConName = tcQual gHC_INTEGER_TYPE (fsLit "Integer") integerTyConKey
integerSDataConName = dcQual gHC_INTEGER_TYPE (fsLit "S#") integerSDataConKey
mkIntegerName = varQual gHC_INTEGER_TYPE (fsLit "mkInteger") mkIntegerIdKey
integerToWord64Name = varQual gHC_INTEGER_TYPE (fsLit "integerToWord64") integerToWord64IdKey
integerToInt64Name = varQual gHC_INTEGER_TYPE (fsLit "integerToInt64") integerToInt64IdKey
......@@ -1169,10 +1193,7 @@ bitIntegerName = varQual gHC_INTEGER_TYPE (fsLit "bitInteger") bit
-- GHC.Natural types
naturalTyConName, naturalSDataConName :: Name
naturalTyConName = tcQual gHC_NATURAL (fsLit "Natural") naturalTyConKey
naturalSDataConName = dcQual gHC_NATURAL (fsLit n) naturalSDataConKey
where n = case cIntegerLibraryType of
IntegerGMP -> "NatS#"
IntegerSimple -> panic "naturalSDataConName evaluated for integer-simple"
naturalSDataConName = dcQual gHC_NATURAL (fsLit "NatS#") naturalSDataConKey
naturalFromIntegerName :: Name
naturalFromIntegerName = varQual gHC_NATURAL (fsLit "naturalFromInteger") naturalFromIntegerIdKey
......
......@@ -60,7 +60,10 @@ library
UnliftedFFITypes
build-depends: ghc-prim ^>= 0.5.1.0
hs-source-dirs: src/
ghc-options: -this-unit-id integer-gmp -Wall
-- We need to set the unit ID to integer-wired-in
-- (without a version number) as it's magic.
-- See Note [The integer library] in PrelNames
ghc-options: -this-unit-id integer-wired-in -Wall
cc-options: -std=c99 -Wall
include-dirs: include
......
......@@ -26,6 +26,7 @@ Library
other-modules: GHC.Integer.Type
default-extensions: CPP, MagicHash, BangPatterns, UnboxedTuples,
UnliftedFFITypes, NoImplicitPrelude
-- We need to set the unit ID to integer-simple
-- We need to set the unit ID to integer-wired-in
-- (without a version number) as it's magic.
ghc-options: -this-unit-id integer-simple -Wall
-- See Note [The integer library] in PrelNames
ghc-options: -this-unit-id integer-wired-in -Wall
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment