ghc-9.12.1: GHC/Driver/Backend.hs
{-# LANGUAGE MultiWayIf, LambdaCase #-}
{-|
Module : GHC.Driver.Backend
Description : Back ends for code generation
This module exports the `Backend` type and all the available values
of that type. The type is abstract, and GHC assumes a "closed world":
all the back ends are known and are known here. The compiler driver
chooses a `Backend` value based on how it is asked to generate code.
A `Backend` value encapsulates the knowledge needed to take Cmm, STG,
or Core and write assembly language to a file. A back end also
provides a function that enables the compiler driver to run an
assembler on the code that is written, if any (the "post-backend
pipeline"). Finally, a back end has myriad /properties/. Properties
mediate interactions between a back end and the rest of the compiler,
especially the driver. Examples include the following:
* Property `backendValidityOfCImport` says whether the back end can
import foreign C functions.
* Property `backendForcesOptimization0` says whether the back end can
be used with optimization levels higher than `-O0`.
* Property `backendCDefs` tells the compiler driver, "if you're using
this back end, then these are the command-line flags you should add
to any invocation of the C compiler."
These properties are used elsewhere in GHC, primarily in the driver, to
fine-tune operations according to the capabilities of the chosen back
end. You might use a property to make GHC aware of a potential
limitation of certain back ends, or a special feature available only
in certain back ends. If your client code needs to know a fact that
is not exposed in an existing property, you would define and export a
new property. Conditioning client code on the /identity/ or /name/ of
a back end is Not Done.
For full details, see the documentation of each property.
-}
module GHC.Driver.Backend
( -- * The @Backend@ type
Backend -- note: type is abstract
-- * Available back ends
, ncgBackend
, llvmBackend
, jsBackend
, viaCBackend
, interpreterBackend
, noBackend
, allBackends
-- * Types used to specify properties of back ends
, PrimitiveImplementation(..)
-- ** Properties that stand for functions
-- *** Back-end function for code generation
, DefunctionalizedCodeOutput(..)
-- *** Back-end functions for assembly
, DefunctionalizedPostHscPipeline(..)
-- *** Other back-end functions
, DefunctionalizedCDefs(..)
-- ** Names of back ends (for API clients of version 9.4 or earlier)
, BackendName
-- * Properties of back ends
, backendDescription
, backendWritesFiles
, backendPipelineOutput
, backendCanReuseLoadedCode
, backendGeneratesCode
, backendGeneratesCodeForHsBoot
, backendSupportsInterfaceWriting
, backendRespectsSpecialise
, backendWantsGlobalBindings
, backendHasNativeSwitch
, backendPrimitiveImplementation
, backendSimdValidity
, backendSupportsEmbeddedBlobs
, backendNeedsPlatformNcgSupport
, backendSupportsUnsplitProcPoints
, backendSwappableWithViaC
, backendUnregisterisedAbiOnly
, backendGeneratesHc
, backendSptIsDynamic
, backendSupportsBreakpoints
, backendForcesOptimization0
, backendNeedsFullWays
, backendSpecialModuleSource
, backendSupportsHpc
, backendSupportsCImport
, backendSupportsCExport
, backendCDefs
, backendCodeOutput
, backendUseJSLinker
, backendPostHscPipeline
, backendNormalSuccessorPhase
, backendName
, backendValidityOfCImport
, backendValidityOfCExport
-- * Other functions of back ends
, platformDefaultBackend
, platformNcgSupported
)
where
import GHC.Prelude
import GHC.Driver.Backend.Internal (BackendName(..))
import GHC.Driver.Phases
import GHC.Utils.Error
import GHC.Utils.Panic
import GHC.Driver.Pipeline.Monad
import GHC.Platform
---------------------------------------------------------------------------------
--
-- DESIGN CONSIDERATIONS
--
--
--
-- The `Backend` type is made abstract in order to make it possible to
-- add new back ends without having to inspect or modify much code
-- elsewhere in GHC. Adding a new back end would be /easiest/ if
-- `Backend` were represented as a record type, but in peer review,
-- the clear will of the majority was to use a sum type. As a result,
-- when adding a new back end it is necessary to modify /every/
-- function in this module that expects `Backend` as its first argument.
-- **By design, these functions have no default/wildcard cases.** This
-- design forces the author of a new back end to consider the semantics
-- in every case, rather than relying on a default that may be wrong.
-- The names and documentation of the functions defined in the `Backend`
-- record are sufficiently descriptive that the author of a new back
-- end will be able to identify correct result values without having to go
-- spelunking throughout the compiler.
--
-- While the design localizes /most/ back-end logic in this module,
-- the author of a new back end will still have to make changes
-- elsewhere in the compiler:
--
-- * For reasons described in Note [Backend Defunctionalization],
-- code-generation and post-backend pipeline functions, among other
-- functions, cannot be placed in the `Backend` record itself.
-- Instead, the /names/ of those functions are placed. Each name is
-- a value constructor in one of the algebraic data types defined in
-- this module. The named function is then defined near its point
-- of use.
--
-- The author of a new back end will have to consider whether an
-- existing function will do or whether a new function needs to be
-- defined. When a new function needs to be defined, the author
-- must take two steps:
--
-- - Add a value constructor to the relevant data type here
-- in the `Backend` module
--
-- - Add a case to the location in the compiler (there should be
-- exactly one) where the value constructors of the relevant
-- data type are used
--
-- * When a new back end is defined, it's quite possible that the
-- compiler driver will have to be changed in some way. Just because
-- the driver supports five back ends doesn't mean it will support a sixth
-- without changes.
--
-- The collection of functions exported from this module hasn't
-- really been "designed"; it's what emerged from a refactoring of
-- older code. The real design criterion was "make it crystal clear
-- what has to be done to add a new back end."
--
-- One issue remains unresolved: some of the error messages and
-- warning messages used in the driver assume a "closed world": they
-- think they know all the back ends that exist, and they are not shy
-- about enumerating them. Just one set of error messages has been
-- ported to have an open-world assumption: these are the error
-- messages associated with type checking of foreign imports and
-- exports. To allow other errors to be issued with an open-world
-- assumption, use functions `backendValidityOfCImport` and
-- `backendValidityOfCExport` as models, and have a look at how the
-- 'expected back ends' are used in modules "GHC.Tc.Gen.Foreign" and
-- "GHC.Tc.Errors.Ppr"
--
---------------------------------------------------------------------------------
platformDefaultBackend :: Platform -> Backend
platformDefaultBackend platform = if
| platformUnregisterised platform -> viaCBackend
| platformNcgSupported platform -> ncgBackend
| platformJSSupported platform -> jsBackend
| otherwise -> llvmBackend
-- | Is the platform supported by the Native Code Generator?
platformNcgSupported :: Platform -> Bool
platformNcgSupported platform = if
| platformUnregisterised platform -> False -- NCG doesn't support unregisterised ABI
| ncgValidArch -> True
| otherwise -> False
where
ncgValidArch = case platformArch platform of
ArchX86 -> True
ArchX86_64 -> True
ArchPPC -> True
ArchPPC_64 {} -> True
ArchAArch64 -> True
ArchWasm32 -> True
ArchRISCV64 -> True
_ -> False
-- | Is the platform supported by the JS backend?
platformJSSupported :: Platform -> Bool
platformJSSupported platform
| platformArch platform == ArchJavaScript = True
| otherwise = False
-- | A value of type @Backend@ represents one of GHC's back ends.
-- The set of back ends cannot be extended except by modifying the
-- definition of @Backend@ in this module.
--
-- The @Backend@ type is abstract; that is, its value constructors are
-- not exported. It's crucial that they not be exported, because a
-- value of type @Backend@ carries only the back end's /name/, not its
-- behavior or properties. If @Backend@ were not abstract, then code
-- elsewhere in the compiler could depend directly on the name, not on
-- the semantics, which would make it challenging to create a new back end.
-- Because @Backend@ /is/ abstract, all the obligations of a new back
-- end are enumerated in this module, in the form of functions that
-- take @Backend@ as an argument.
--
-- The issue of abstraction is discussed at great length in #20927 and !7442.
newtype Backend = Named BackendName
-- Must be a newtype so that it has no `Eq` instance and
-- a different `Show` instance.
-- | The Show instance is for messages /only/. If code depends on
-- what's in the string, you deserve what happens to you.
instance Show Backend where
show = backendDescription
ncgBackend, llvmBackend, viaCBackend, interpreterBackend, jsBackend, noBackend
:: Backend
-- | The native code generator.
-- Compiles Cmm code into textual assembler, then relies on
-- an external assembler toolchain to produce machine code.
--
-- Only supports a few platforms (X86, PowerPC, SPARC).
--
-- See "GHC.CmmToAsm".
ncgBackend = Named NCG
-- | The LLVM backend.
--
-- Compiles Cmm code into LLVM textual IR, then relies on
-- LLVM toolchain to produce machine code.
--
-- It relies on LLVM support for the calling convention used
-- by the NCG backend to produce code objects ABI compatible
-- with it (see "cc 10" or "ghccc" calling convention in
-- https://llvm.org/docs/LangRef.html#calling-conventions).
--
-- Supports a few platforms (X86, AArch64, s390x, ARM).
--
-- See "GHC.CmmToLlvm"
llvmBackend = Named LLVM
-- | The JavaScript Backend
--
-- See documentation in GHC.StgToJS
jsBackend = Named JavaScript
-- | Via-C ("unregisterised") backend.
--
-- Compiles Cmm code into C code, then relies on a C compiler
-- to produce machine code.
--
-- It produces code objects that are /not/ ABI compatible
-- with those produced by NCG and LLVM backends.
--
-- Produced code is expected to be less efficient than the
-- one produced by NCG and LLVM backends because STG
-- registers are not pinned into real registers. On the
-- other hand, it supports more target platforms (those
-- having a valid C toolchain).
--
-- See "GHC.CmmToC"
viaCBackend = Named ViaC
-- | The ByteCode interpreter.
--
-- Produce ByteCode objects (BCO, see "GHC.ByteCode") that
-- can be interpreted. It is used by GHCi.
--
-- Currently some extensions are not supported
-- (foreign primops).
--
-- See "GHC.StgToByteCode"
interpreterBackend = Named Interpreter
-- | A dummy back end that generates no code.
--
-- Use this back end to disable code generation. It is particularly
-- useful when GHC is used as a library for other purpose than
-- generating code (e.g. to generate documentation with Haddock) or
-- when the user requested it (via `-fno-code`) for some reason.
noBackend = Named NoBackend
---------------------------------------------------------------------------------
-- | This enumeration type specifies how the back end wishes GHC's
-- primitives to be implemented. (Module "GHC.StgToCmm.Prim" provides
-- a generic implementation of every primitive, but some primitives,
-- like `IntQuotRemOp`, can be implemented more efficiently by
-- certain back ends on certain platforms. For example, by using a
-- machine instruction that simultaneously computes quotient and remainder.)
--
-- For the meaning of each alternative, consult
-- "GHC.StgToCmm.Config". (In a perfect world, type
-- `PrimitiveImplementation` would be defined there, in the module
-- that determines its meaning. But I could not figure out how to do
-- it without mutual recursion across module boundaries.)
data PrimitiveImplementation
= LlvmPrimitives -- ^ Primitives supported by LLVM
| NcgPrimitives -- ^ Primitives supported by the native code generator
| JSPrimitives -- ^ Primitives supported by JS backend
| GenericPrimitives -- ^ Primitives supported by all back ends
deriving Show
-- | Names a function that generates code and writes the results to a
-- file, of this type:
--
-- > Logger
-- > -> DynFlags
-- > -> Module -- ^ module being compiled
-- > -> ModLocation
-- > -> FilePath -- ^ Where to write output
-- > -> Set UnitId -- ^ dependencies
-- > -> Stream IO RawCmmGroup a -- results from `StgToCmm`
-- > -> IO a
--
-- The functions so named are defined in "GHC.Driver.CodeOutput".
--
-- We expect one function per back end—or more precisely, one function
-- for each back end that writes code to a file. (The interpreter
-- does not write to files; its output lives only in memory.)
data DefunctionalizedCodeOutput
= NcgCodeOutput
| ViaCCodeOutput
| LlvmCodeOutput
| JSCodeOutput
-- | Names a function that tells the driver what should happen after
-- assembly code is written. This might include running a C compiler,
-- running LLVM, running an assembler, or various similar activities.
-- The function named normally has this type:
--
-- > TPipelineClass TPhase m
-- > => PipeEnv
-- > -> HscEnv
-- > -> Maybe ModLocation
-- > -> FilePath
-- > -> m (Maybe FilePath)
--
-- The functions so named are defined in "GHC.Driver.Pipeline".
data DefunctionalizedPostHscPipeline
= NcgPostHscPipeline
| ViaCPostHscPipeline
| LlvmPostHscPipeline
| JSPostHscPipeline
| NoPostHscPipeline -- ^ After code generation, nothing else need happen.
-- | Names a function that tells the driver what command-line options
-- to include when invoking a C compiler. It's meant for @-D@ options that
-- define symbols for the C preprocessor. Because the exact symbols
-- defined might depend on versions of tools located in the file
-- system (/cough/ LLVM /cough/), the function requires an `IO` action.
-- The function named has this type:
--
-- > Logger -> DynFlags -> IO [String]
data DefunctionalizedCDefs
= NoCDefs -- ^ No additional command-line options are needed
| LlvmCDefs -- ^ Return command-line options that tell GHC about the
-- LLVM version.
---------------------------------------------------------------------------------
-- | An informal description of the back end, for use in
-- issuing warning messages /only/. If code depends on
-- what's in the string, you deserve what happens to you.
backendDescription :: Backend -> String
backendDescription (Named NCG) = "native code generator"
backendDescription (Named LLVM) = "LLVM"
backendDescription (Named ViaC) = "compiling via C"
backendDescription (Named JavaScript) = "compiling to JavaScript"
backendDescription (Named Interpreter) = "byte-code interpreter"
backendDescription (Named NoBackend) = "no code generated"
-- | This flag tells the compiler driver whether the back
-- end will write files: interface files and object files.
-- It is typically true for "real" back ends that generate
-- code into the filesystem. (That means, not the interpreter.)
backendWritesFiles :: Backend -> Bool
backendWritesFiles (Named NCG) = True
backendWritesFiles (Named LLVM) = True
backendWritesFiles (Named ViaC) = True
backendWritesFiles (Named JavaScript) = True
backendWritesFiles (Named Interpreter) = False
backendWritesFiles (Named NoBackend) = False
-- | When the back end does write files, this value tells
-- the compiler in what manner of file the output should go:
-- temporary, persistent, or specific.
backendPipelineOutput :: Backend -> PipelineOutput
backendPipelineOutput (Named NCG) = Persistent
backendPipelineOutput (Named LLVM) = Persistent
backendPipelineOutput (Named ViaC) = Persistent
backendPipelineOutput (Named JavaScript) = Persistent
backendPipelineOutput (Named Interpreter) = NoOutputFile
backendPipelineOutput (Named NoBackend) = NoOutputFile
-- | This flag tells the driver whether the back end can
-- reuse code (bytecode or object code) that has been
-- loaded dynamically. Likely true only of the interpreter.
backendCanReuseLoadedCode :: Backend -> Bool
backendCanReuseLoadedCode (Named NCG) = False
backendCanReuseLoadedCode (Named LLVM) = False
backendCanReuseLoadedCode (Named ViaC) = False
backendCanReuseLoadedCode (Named JavaScript) = False
backendCanReuseLoadedCode (Named Interpreter) = True
backendCanReuseLoadedCode (Named NoBackend) = False
-- | It is is true of every back end except @-fno-code@
-- that it "generates code." Surprisingly, this property
-- influences the driver in a ton of ways. Some examples:
--
-- * If the back end does not generate code, then the
-- driver needs to turn on code generation for
-- Template Haskell (because that code needs to be
-- generated and run at compile time).
--
-- * If the back end does not generate code, then the
-- driver does not need to deal with an output file.
--
-- * If the back end /does/ generated code, then the
-- driver supports `HscRecomp`. If not, recompilation
-- does not need a linkable (and is automatically up
-- to date).
--
backendGeneratesCode :: Backend -> Bool
backendGeneratesCode (Named NCG) = True
backendGeneratesCode (Named LLVM) = True
backendGeneratesCode (Named ViaC) = True
backendGeneratesCode (Named JavaScript) = True
backendGeneratesCode (Named Interpreter) = True
backendGeneratesCode (Named NoBackend) = False
backendGeneratesCodeForHsBoot :: Backend -> Bool
backendGeneratesCodeForHsBoot (Named NCG) = True
backendGeneratesCodeForHsBoot (Named LLVM) = True
backendGeneratesCodeForHsBoot (Named ViaC) = True
backendGeneratesCodeForHsBoot (Named JavaScript) = True
backendGeneratesCodeForHsBoot (Named Interpreter) = False
backendGeneratesCodeForHsBoot (Named NoBackend) = False
-- | When set, this flag turns on interface writing for
-- Backpack. It should probably be the same as
-- `backendGeneratesCode`, but it is kept distinct for
-- reasons described in Note [-fno-code mode].
backendSupportsInterfaceWriting :: Backend -> Bool
backendSupportsInterfaceWriting (Named NCG) = True
backendSupportsInterfaceWriting (Named LLVM) = True
backendSupportsInterfaceWriting (Named ViaC) = True
backendSupportsInterfaceWriting (Named JavaScript) = True
backendSupportsInterfaceWriting (Named Interpreter) = True
backendSupportsInterfaceWriting (Named NoBackend) = False
-- | When preparing code for this back end, the type
-- checker should pay attention to SPECIALISE pragmas. If
-- this flag is `False`, then the type checker ignores
-- SPECIALISE pragmas (for imported things?).
backendRespectsSpecialise :: Backend -> Bool
backendRespectsSpecialise (Named NCG) = True
backendRespectsSpecialise (Named LLVM) = True
backendRespectsSpecialise (Named ViaC) = True
backendRespectsSpecialise (Named JavaScript) = True
backendRespectsSpecialise (Named Interpreter) = False
backendRespectsSpecialise (Named NoBackend) = False
-- | This back end wants the `mi_top_env` field of a
-- `ModIface` to be populated (with the top-level bindings
-- of the original source). Only true for the interpreter.
backendWantsGlobalBindings :: Backend -> Bool
backendWantsGlobalBindings (Named NCG) = False
backendWantsGlobalBindings (Named LLVM) = False
backendWantsGlobalBindings (Named ViaC) = False
backendWantsGlobalBindings (Named JavaScript) = False
backendWantsGlobalBindings (Named NoBackend) = False
backendWantsGlobalBindings (Named Interpreter) = True
-- | The back end targets a technology that implements
-- `switch` natively. (For example, LLVM or C.) Therefore
-- it is not necessary for GHC to ccompile a Cmm `Switch`
-- form into a decision tree with jump tables at the
-- leaves.
backendHasNativeSwitch :: Backend -> Bool
backendHasNativeSwitch (Named NCG) = False
backendHasNativeSwitch (Named LLVM) = True
backendHasNativeSwitch (Named ViaC) = True
backendHasNativeSwitch (Named JavaScript) = True
backendHasNativeSwitch (Named Interpreter) = False
backendHasNativeSwitch (Named NoBackend) = False
-- | As noted in the documentation for
-- `PrimitiveImplementation`, certain primitives have
-- multiple implementations, depending on the capabilities
-- of the back end. This field signals to module
-- "GHC.StgToCmm.Prim" what implementations to use with
-- this back end.
backendPrimitiveImplementation :: Backend -> PrimitiveImplementation
backendPrimitiveImplementation (Named NCG) = NcgPrimitives
backendPrimitiveImplementation (Named LLVM) = LlvmPrimitives
backendPrimitiveImplementation (Named JavaScript) = JSPrimitives
backendPrimitiveImplementation (Named ViaC) = GenericPrimitives
backendPrimitiveImplementation (Named Interpreter) = GenericPrimitives
backendPrimitiveImplementation (Named NoBackend) = GenericPrimitives
-- | When this value is `IsValid`, the back end is
-- compatible with vector instructions. When it is
-- `NotValid`, it carries a message that is shown to
-- users.
backendSimdValidity :: Backend -> Validity' String
backendSimdValidity (Named NCG) = IsValid
backendSimdValidity (Named LLVM) = IsValid
backendSimdValidity (Named ViaC) = NotValid $ unlines ["SIMD vector instructions require using the NCG or the LLVM backend."]
backendSimdValidity (Named JavaScript) = NotValid $ unlines ["SIMD vector instructions require using the NCG or the LLVM backend."]
backendSimdValidity (Named Interpreter) = NotValid $ unlines ["SIMD vector instructions require using the NCG or the LLVM backend."]
backendSimdValidity (Named NoBackend) = NotValid $ unlines ["SIMD vector instructions require using the NCG or the LLVM backend."]
-- | This flag says whether the back end supports large
-- binary blobs. See Note [Embedding large binary blobs]
-- in "GHC.CmmToAsm.Ppr".
backendSupportsEmbeddedBlobs :: Backend -> Bool
backendSupportsEmbeddedBlobs (Named NCG) = True
backendSupportsEmbeddedBlobs (Named LLVM) = False
backendSupportsEmbeddedBlobs (Named ViaC) = False
backendSupportsEmbeddedBlobs (Named JavaScript) = False
backendSupportsEmbeddedBlobs (Named Interpreter) = False
backendSupportsEmbeddedBlobs (Named NoBackend) = False
-- | This flag tells the compiler driver that the back end
-- does not support every target platform; it supports
-- only platforms that claim NCG support. (It's set only
-- for the native code generator.) Crufty. If the driver
-- tries to use the native code generator /without/
-- platform support, the driver fails over to the LLVM
-- back end.
backendNeedsPlatformNcgSupport :: Backend -> Bool
backendNeedsPlatformNcgSupport (Named NCG) = True
backendNeedsPlatformNcgSupport (Named LLVM) = False
backendNeedsPlatformNcgSupport (Named ViaC) = False
backendNeedsPlatformNcgSupport (Named JavaScript) = False
backendNeedsPlatformNcgSupport (Named Interpreter) = False
backendNeedsPlatformNcgSupport (Named NoBackend) = False
-- | This flag is set if the back end can generate code
-- for proc points. If the flag is not set, then a Cmm
-- pass needs to split proc points (that is, turn each
-- proc point into a standalone procedure).
backendSupportsUnsplitProcPoints :: Backend -> Bool
backendSupportsUnsplitProcPoints (Named NCG) = True
backendSupportsUnsplitProcPoints (Named LLVM) = False
backendSupportsUnsplitProcPoints (Named ViaC) = False
backendSupportsUnsplitProcPoints (Named JavaScript) = False
backendSupportsUnsplitProcPoints (Named Interpreter) = False
backendSupportsUnsplitProcPoints (Named NoBackend) = False
-- | This flag guides the driver in resolving issues about
-- API support on the target platform. If the flag is set,
-- then these things are true:
--
-- * When the target platform supports /only/ an unregisterised API,
-- this backend can be replaced with compilation via C.
--
-- * When the target does /not/ support an unregisterised API,
-- this back end can replace compilation via C.
--
backendSwappableWithViaC :: Backend -> Bool
backendSwappableWithViaC (Named NCG) = True
backendSwappableWithViaC (Named LLVM) = True
backendSwappableWithViaC (Named ViaC) = False
backendSwappableWithViaC (Named JavaScript) = False
backendSwappableWithViaC (Named Interpreter) = False
backendSwappableWithViaC (Named NoBackend) = False
-- | This flag is true if the back end works *only* with
-- the unregisterised ABI.
backendUnregisterisedAbiOnly :: Backend -> Bool
backendUnregisterisedAbiOnly (Named NCG) = False
backendUnregisterisedAbiOnly (Named LLVM) = False
backendUnregisterisedAbiOnly (Named ViaC) = True
backendUnregisterisedAbiOnly (Named JavaScript) = False
backendUnregisterisedAbiOnly (Named Interpreter) = False
backendUnregisterisedAbiOnly (Named NoBackend) = False
-- | This flag is set if the back end generates C code in
-- a @.hc@ file. The flag lets the compiler driver know
-- if the command-line flag @-C@ is meaningful.
backendGeneratesHc :: Backend -> Bool
backendGeneratesHc (Named NCG) = False
backendGeneratesHc (Named LLVM) = False
backendGeneratesHc (Named ViaC) = True
backendGeneratesHc (Named JavaScript) = False
backendGeneratesHc (Named Interpreter) = False
backendGeneratesHc (Named NoBackend) = False
-- | This flag says whether SPT (static pointer table)
-- entries will be inserted dynamically if needed. If
-- this flag is `False`, then "GHC.Iface.Tidy" should emit C
-- stubs that initialize the SPT entries.
backendSptIsDynamic :: Backend -> Bool
backendSptIsDynamic (Named NCG) = False
backendSptIsDynamic (Named LLVM) = False
backendSptIsDynamic (Named ViaC) = False
backendSptIsDynamic (Named JavaScript) = False
backendSptIsDynamic (Named Interpreter) = True
backendSptIsDynamic (Named NoBackend) = False
-- | If this flag is unset, then the driver ignores the flag @-fbreak-points@,
-- since backends other than the interpreter tend to panic on breakpoints.
backendSupportsBreakpoints :: Backend -> Bool
backendSupportsBreakpoints = \case
Named NCG -> False
Named LLVM -> False
Named ViaC -> False
Named JavaScript -> False
Named Interpreter -> True
Named NoBackend -> False
-- | If this flag is set, then the driver forces the
-- optimization level to 0, issuing a warning message if
-- the command line requested a higher optimization level.
backendForcesOptimization0 :: Backend -> Bool
backendForcesOptimization0 (Named NCG) = False
backendForcesOptimization0 (Named LLVM) = False
backendForcesOptimization0 (Named ViaC) = False
backendForcesOptimization0 (Named JavaScript) = False
backendForcesOptimization0 (Named Interpreter) = True
backendForcesOptimization0 (Named NoBackend) = False
-- | I don't understand exactly how this works. But if
-- this flag is set *and* another condition is met, then
-- @ghc/Main.hs@ will alter the `DynFlags` so that all the
-- `hostFullWays` are asked for. It is set only for the interpreter.
backendNeedsFullWays :: Backend -> Bool
backendNeedsFullWays (Named NCG) = False
backendNeedsFullWays (Named LLVM) = False
backendNeedsFullWays (Named ViaC) = False
backendNeedsFullWays (Named JavaScript) = False
backendNeedsFullWays (Named Interpreter) = True
backendNeedsFullWays (Named NoBackend) = False
-- | This flag is also special for the interpreter: if a
-- message about a module needs to be shown, do we know
-- anything special about where the module came from? The
-- Boolean argument is a `recomp` flag.
backendSpecialModuleSource :: Backend -> Bool -> Maybe String
backendSpecialModuleSource (Named NCG) = const Nothing
backendSpecialModuleSource (Named LLVM) = const Nothing
backendSpecialModuleSource (Named ViaC) = const Nothing
backendSpecialModuleSource (Named JavaScript) = const Nothing
backendSpecialModuleSource (Named Interpreter) = \b -> if b then Just "interpreted" else Nothing
backendSpecialModuleSource (Named NoBackend) = const (Just "nothing")
-- | This flag says whether the back end supports Haskell
-- Program Coverage (HPC). If not, the compiler driver
-- will ignore the `-fhpc` option (and will issue a
-- warning message if it is used).
backendSupportsHpc :: Backend -> Bool
backendSupportsHpc (Named NCG) = True
backendSupportsHpc (Named LLVM) = True
backendSupportsHpc (Named ViaC) = True
backendSupportsHpc (Named JavaScript) = False
backendSupportsHpc (Named Interpreter) = False
backendSupportsHpc (Named NoBackend) = True
-- | This flag says whether the back end supports foreign
-- import of C functions. ("Supports" means "does not
-- barf on," so @-fno-code@ supports foreign C imports.)
backendSupportsCImport :: Backend -> Bool
backendSupportsCImport (Named NCG) = True
backendSupportsCImport (Named LLVM) = True
backendSupportsCImport (Named ViaC) = True
backendSupportsCImport (Named JavaScript) = True
backendSupportsCImport (Named Interpreter) = True
backendSupportsCImport (Named NoBackend) = True
-- | This flag says whether the back end supports foreign
-- export of Haskell functions to C.
backendSupportsCExport :: Backend -> Bool
backendSupportsCExport (Named NCG) = True
backendSupportsCExport (Named LLVM) = True
backendSupportsCExport (Named ViaC) = True
backendSupportsCExport (Named JavaScript) = True
backendSupportsCExport (Named Interpreter) = False
backendSupportsCExport (Named NoBackend) = True
-- | When using this back end, it may be necessary or
-- advisable to pass some `-D` options to a C compiler.
-- This (defunctionalized) function produces those
-- options, if any. An IO action may be necessary in
-- order to interrogate external tools about what version
-- they are, for example.
--
-- The function's type is
-- @
-- Logger -> DynFlags -> IO [String]
-- @
--
-- This field is usually defaulted.
backendCDefs :: Backend -> DefunctionalizedCDefs
backendCDefs (Named NCG) = NoCDefs
backendCDefs (Named LLVM) = LlvmCDefs
backendCDefs (Named ViaC) = NoCDefs
backendCDefs (Named JavaScript) = NoCDefs
backendCDefs (Named Interpreter) = NoCDefs
backendCDefs (Named NoBackend) = NoCDefs
-- | This (defunctionalized) function generates code and
-- writes it to a file. The type of the function is
--
-- > Logger
-- > -> DynFlags
-- > -> Module -- ^ module being compiled
-- > -> ModLocation
-- > -> FilePath -- ^ Where to write output
-- > -> Set UnitId -- ^ dependencies
-- > -> Stream IO RawCmmGroup a -- results from `StgToCmm`
-- > -> IO a
backendCodeOutput :: Backend -> DefunctionalizedCodeOutput
backendCodeOutput (Named NCG) = NcgCodeOutput
backendCodeOutput (Named LLVM) = LlvmCodeOutput
backendCodeOutput (Named ViaC) = ViaCCodeOutput
backendCodeOutput (Named JavaScript) = JSCodeOutput
backendCodeOutput (Named Interpreter) = panic "backendCodeOutput: interpreterBackend"
backendCodeOutput (Named NoBackend) = panic "backendCodeOutput: noBackend"
backendUseJSLinker :: Backend -> Bool
backendUseJSLinker (Named NCG) = False
backendUseJSLinker (Named LLVM) = False
backendUseJSLinker (Named ViaC) = False
backendUseJSLinker (Named JavaScript) = True
backendUseJSLinker (Named Interpreter) = False
backendUseJSLinker (Named NoBackend) = False
-- | This (defunctionalized) function tells the compiler
-- driver what else has to be run after code output.
-- The type of the function is
--
-- >
-- > TPipelineClass TPhase m
-- > => PipeEnv
-- > -> HscEnv
-- > -> Maybe ModLocation
-- > -> FilePath
-- > -> m (Maybe FilePath)
backendPostHscPipeline :: Backend -> DefunctionalizedPostHscPipeline
backendPostHscPipeline (Named NCG) = NcgPostHscPipeline
backendPostHscPipeline (Named LLVM) = LlvmPostHscPipeline
backendPostHscPipeline (Named ViaC) = ViaCPostHscPipeline
backendPostHscPipeline (Named JavaScript) = JSPostHscPipeline
backendPostHscPipeline (Named Interpreter) = NoPostHscPipeline
backendPostHscPipeline (Named NoBackend) = NoPostHscPipeline
-- | Somewhere in the compiler driver, when compiling
-- Haskell source (as opposed to a boot file or a sig
-- file), it needs to know what to do with the code that
-- the `backendCodeOutput` writes to a file. This `Phase`
-- value gives instructions like "run the C compiler",
-- "run the assembler," or "run the LLVM Optimizer."
backendNormalSuccessorPhase :: Backend -> Phase
backendNormalSuccessorPhase (Named NCG) = As False
backendNormalSuccessorPhase (Named LLVM) = LlvmOpt
backendNormalSuccessorPhase (Named ViaC) = HCc
backendNormalSuccessorPhase (Named JavaScript) = StopLn
backendNormalSuccessorPhase (Named Interpreter) = StopLn
backendNormalSuccessorPhase (Named NoBackend) = StopLn
-- | Name of the back end, if any. Used to migrate legacy
-- clients of the GHC API. Code within the GHC source
-- tree should not refer to a back end's name.
backendName :: Backend -> BackendName
backendName (Named NCG) = NCG
backendName (Named LLVM) = LLVM
backendName (Named ViaC) = ViaC
backendName (Named JavaScript) = JavaScript
backendName (Named Interpreter) = Interpreter
backendName (Named NoBackend) = NoBackend
-- | A list of all back ends. They are ordered as we wish them to
-- appear when they are enumerated in error messages.
allBackends :: [Backend]
allBackends = [ ncgBackend
, llvmBackend
, viaCBackend
, jsBackend
, interpreterBackend
, noBackend
]
-- | When foreign C import or export is invalid, the carried value
-- enumerates the /valid/ back ends.
backendValidityOfCImport, backendValidityOfCExport :: Backend -> Validity' [Backend]
backendValidityOfCImport backend =
if backendSupportsCImport backend then
IsValid
else
NotValid $ filter backendSupportsCImport allBackends
backendValidityOfCExport backend =
if backendSupportsCExport backend then
IsValid
else
NotValid $ filter backendSupportsCExport allBackends
{-
Note [Backend Defunctionalization]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I had hoped to include code-output and post-hsc-pipeline functions
directly in the `Backend` record itself. But this agenda was derailed
by mutual recursion in the types:
- A `DynFlags` record contains a back end of type `Backend`.
- A `Backend` contains a code-output function.
- A code-output function takes Cmm as input.
- Cmm can include a `CLabel`.
- A `CLabel` can have elements that are defined in
`GHC.Driver.Session`, where `DynFlags` is defined.
There is also a nasty issue in the values: a typical post-backend
pipeline function both depends on and is depended upon by functions in
"GHC.Driver.Pipeline".
I'm cut the Gordian not by removing the function types from the
`Backend` record. Instead, a function is represented by its /name/.
This representation is an example of an old trick called
/defunctionalization/, which has been used in both compilers and
interpreters for languages with first-class, nested functions. Here,
a function's name is a value of an algebraic data type. For example,
a code-output function is represented by a value of this type:
data DefunctionalizedCodeOutput
= NcgCodeOutput
| ViaCCodeOutput
| LlvmCodeOutput
Such a function may be applied in one of two ways:
- In this particular example, a `case` expression in module
"GHC.Driver.CodeOutput" discriminates on the value and calls the
designated function.
- In another example, a function of type `DefunctionalizedCDefs` is
applied by calling function `applyCDefs`, which has this type:
@
applyCDefs :: DefunctionalizedCDefs -> Logger -> DynFlags -> IO [String]
@
Function `applyCDefs` is defined in module "GHC.SysTools.Cpp".
I don't love this solution, but defunctionalization is a standard
thing, and it makes the meanings of the enumeration values clear.
Anyone defining a new back end will need to extend both the
`DefunctionalizedCodeOutput` type and the corresponding apply
function.
-}