llvm-party-12.1.0: src/LLVM/Internal/Target.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
module LLVM.Internal.Target where
import LLVM.Prelude
import Control.Monad.AnyCont
import Control.Monad.Catch
import Control.Monad.IO.Class
import Control.Monad.Trans.Except
import Data.Attoparsec.ByteString
import Data.Attoparsec.ByteString.Char8
import Data.Char
import Data.Map (Map)
import Foreign.C.String
import Foreign.Ptr
import qualified Data.ByteString as ByteString
import qualified Data.Map as Map
#if __GLASGOW_HASKELL__ < 808
import Control.Monad.Fail (MonadFail)
#endif
import LLVM.Internal.Coding
import LLVM.Internal.String ()
import LLVM.Internal.LibraryFunction
import LLVM.DataLayout
import LLVM.Exception
import LLVM.AST.DataLayout
import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
import qualified LLVM.Internal.FFI.Target as FFI
import qualified LLVM.Relocation as Reloc
import qualified LLVM.Target.Options as TO
import qualified LLVM.CodeModel as CodeModel
import qualified LLVM.CodeGenOpt as CodeGenOpt
genCodingInstance [t| Reloc.Model |] ''FFI.RelocModel [
(FFI.relocModelDefault, Reloc.Default),
(FFI.relocModelStatic, Reloc.Static),
(FFI.relocModelPIC, Reloc.PIC),
(FFI.relocModelDynamicNoPic, Reloc.DynamicNoPIC)
]
genCodingInstance [t| CodeModel.Model |] ''FFI.CodeModel [
(FFI.codeModelDefault,CodeModel.Default),
(FFI.codeModelJITDefault, CodeModel.JITDefault),
(FFI.codeModelSmall, CodeModel.Small),
(FFI.codeModelKernel, CodeModel.Kernel),
(FFI.codeModelMedium, CodeModel.Medium),
(FFI.codeModelLarge, CodeModel.Large)
]
genCodingInstance [t| CodeGenOpt.Level |] ''FFI.CodeGenOptLevel [
(FFI.codeGenOptLevelNone, CodeGenOpt.None),
(FFI.codeGenOptLevelLess, CodeGenOpt.Less),
(FFI.codeGenOptLevelDefault, CodeGenOpt.Default),
(FFI.codeGenOptLevelAggressive, CodeGenOpt.Aggressive)
]
genCodingInstance [t| TO.FloatABI |] ''FFI.FloatABIType [
(FFI.floatABIDefault, TO.FloatABIDefault),
(FFI.floatABISoft, TO.FloatABISoft),
(FFI.floatABIHard, TO.FloatABIHard)
]
genCodingInstance [t| TO.FloatingPointOperationFusionMode |] ''FFI.FPOpFusionMode [
(FFI.fpOpFusionModeFast, TO.FloatingPointOperationFusionFast),
(FFI.fpOpFusionModeStandard, TO.FloatingPointOperationFusionStandard),
(FFI.fpOpFusionModeStrict, TO.FloatingPointOperationFusionStrict)
]
genCodingInstance[t| TO.DebugCompressionType |] ''FFI.DebugCompressionType [
(FFI.debugCompressionTypeNone, TO.CompressNone),
(FFI.debugCompressionTypeGNU, TO.CompressGNU),
(FFI.debugCompressionTypeZ, TO.CompressZ)
]
genCodingInstance[t| TO.ThreadModel |] ''FFI.ThreadModel [
(FFI.threadModelPOSIX, TO.ThreadModelPOSIX),
(FFI.threadModelSingle, TO.ThreadModelSingle)
]
genCodingInstance[t| TO.EABIVersion |] ''FFI.EABI [
(FFI.eabiVersionUnknown, TO.EABIVersionUnknown),
(FFI.eabiVersionDefault, TO.EABIVersionDefault),
(FFI.eabiVersionEABI4, TO.EABIVersion4),
(FFI.eabiVersionEABI5, TO.EABIVersion5),
(FFI.eabiVersionGNU, TO.EABIVersionGNU)
]
genCodingInstance[t| TO.DebuggerKind |] ''FFI.DebuggerKind [
(FFI.debuggerKindDefault, TO.DebuggerDefault),
(FFI.debuggerKindGDB, TO.DebuggerGDB),
(FFI.debuggerKindLLDB, TO.DebuggerLLDB),
(FFI.debuggerKindSCE, TO.DebuggerSCE)
]
genCodingInstance[t| TO.FloatingPointDenormalMode |] ''FFI.FPDenormalMode [
(FFI.fpDenormalModeIEEE, TO.FloatingPointDenormalIEEE),
(FFI.fpDenormalModePreserveSign, TO.FloatingPointDenormalPreserveSign),
(FFI.fpDenormalModePositiveZero, TO.FloatingPointDenormalPositiveZero)
]
genCodingInstance[t| TO.ExceptionHandling |] ''FFI.ExceptionHandling [
(FFI.exceptionHandlingNone, TO.ExceptionHandlingNone),
(FFI.exceptionHandlingDwarfCFI, TO.ExceptionHandlingDwarfCFI),
(FFI.exceptionHandlingSjLj, TO.ExceptionHandlingSjLj),
(FFI.exceptionHandlingARM, TO.ExceptionHandlingARM),
(FFI.exceptionHandlingWinEH, TO.ExceptionHandlingWinEH)
]
-- | <http://llvm.org/doxygen/classllvm_1_1Target.html>
newtype Target = Target (Ptr FFI.Target)
-- | e.g. an instruction set extension
newtype CPUFeature = CPUFeature ByteString
deriving (Eq, Ord, Read, Show)
instance EncodeM e ByteString es => EncodeM e (Map CPUFeature Bool) es where
encodeM = encodeM . ByteString.intercalate "," . map (\(CPUFeature f, enabled) -> (if enabled then "+" else "-") <> f) . Map.toList
instance (MonadFail d, DecodeM d ByteString es) => DecodeM d (Map CPUFeature Bool) es where
decodeM es = do
s <- decodeM es
let flag = do
en <- choice [char8 '-' >> return False, char8 '+' >> return True]
s <- ByteString.pack <$> many1 (notWord8 (fromIntegral (ord ',')))
return (CPUFeature s, en)
features = liftM Map.fromList (flag `sepBy` (char8 ','))
case parseOnly (features <* endOfInput) s of
Right features -> return features
Left err -> fail ("failure to parse CPUFeature string: " <> err)
-- | Find a 'Target' given an architecture and/or a \"triple\".
-- | <http://llvm.org/doxygen/structllvm_1_1TargetRegistry.html#a3105b45e546c9cc3cf78d0f2ec18ad89>
-- | Be sure to run either 'initializeAllTargets' or
-- 'initializeNativeTarget' before expecting this to succeed,
-- depending on what target(s) you want to use. May throw
-- 'LookupTargetException' if no target is found.
lookupTarget ::
Maybe ShortByteString -- ^ arch
-> ShortByteString -- ^ \"triple\" - e.g. x86_64-unknown-linux-gnu
-> IO (Target, ShortByteString)
lookupTarget arch triple = runAnyContT' return $ do
cErrorP <- alloca
cNewTripleP <- alloca
arch <- encodeM (maybe "" id arch)
triple <- encodeM triple
target <- liftIO $ FFI.lookupTarget arch triple cNewTripleP cErrorP
when (target == nullPtr) $ throwM . LookupTargetException =<< decodeM cErrorP
liftM (Target target, ) $ decodeM cNewTripleP
-- | <http://llvm.org/doxygen/classllvm_1_1TargetOptions.html>
newtype TargetOptions = TargetOptions (Ptr FFI.TargetOptions)
newtype MCTargetOptions = MCTargetOptions (Ptr FFI.MCTargetOptions)
-- | bracket creation and destruction of a 'TargetOptions' object
withTargetOptions :: (TargetOptions -> IO a) -> IO a
withTargetOptions = bracket FFI.createTargetOptions FFI.disposeTargetOptions . (. TargetOptions)
-- | set all target options
pokeTargetOptions :: TO.Options -> TargetOptions -> IO ()
pokeTargetOptions hOpts opts@(TargetOptions cOpts) = do
mapM_ (\(c, ha) -> FFI.setTargetOptionFlag cOpts c =<< encodeM (ha hOpts)) [
(FFI.targetOptionFlagUnsafeFPMath, TO.unsafeFloatingPointMath),
(FFI.targetOptionFlagNoInfsFPMath, TO.noInfinitiesFloatingPointMath),
(FFI.targetOptionFlagNoNaNsFPMath, TO.noNaNsFloatingPointMath),
(FFI.targetOptionFlagNoTrappingFPMath, TO.noTrappingFloatingPointMath),
(FFI.targetOptionFlagNoSignedZerosFPMath, TO.noSignedZeroesFloatingPointMath),
(FFI.targetOptionFlagHonorSignDependentRoundingFPMathOption, TO.honorSignDependentRoundingFloatingPointMathOption),
(FFI.targetOptionFlagNoZerosInBSS, TO.noZerosInBSS),
(FFI.targetOptionFlagGuaranteedTailCallOpt, TO.guaranteedTailCallOptimization),
(FFI.targetOptionFlagStackSymbolOrdering, TO.stackSymbolOrdering),
(FFI.targetOptionFlagEnableFastISel, TO.enableFastInstructionSelection),
(FFI.targetOptionFlagUseInitArray, TO.useInitArray),
(FFI.targetOptionFlagDisableIntegratedAS, TO.disableIntegratedAssembler),
(FFI.targetOptionFlagRelaxELFRelocations, TO.relaxELFRelocations),
(FFI.targetOptionFlagFunctionSections, TO.functionSections),
(FFI.targetOptionFlagDataSections, TO.dataSections),
(FFI.targetOptionFlagUniqueSectionNames, TO.uniqueSectionNames),
(FFI.targetOptionFlagTrapUnreachable, TO.trapUnreachable),
(FFI.targetOptionFlagEmulatedTLS, TO.emulatedThreadLocalStorage),
(FFI.targetOptionFlagEnableIPRA, TO.enableInterProceduralRegisterAllocation)
]
FFI.setStackAlignmentOverride cOpts =<< encodeM (TO.stackAlignmentOverride hOpts)
FFI.setFloatABIType cOpts =<< encodeM (TO.floatABIType hOpts)
FFI.setAllowFPOpFusion cOpts =<< encodeM (TO.allowFloatingPointOperationFusion hOpts)
FFI.setCompressDebugSections cOpts =<< encodeM (TO.compressDebugSections hOpts)
FFI.setThreadModel cOpts =<< encodeM (TO.threadModel hOpts)
FFI.setEABIVersion cOpts =<< encodeM (TO.eabiVersion hOpts)
FFI.setDebuggerTuning cOpts =<< encodeM (TO.debuggerTuning hOpts)
FFI.setFPDenormalMode cOpts =<< encodeM (TO.floatingPointDenormalMode hOpts)
FFI.setExceptionModel cOpts =<< encodeM (TO.exceptionModel hOpts)
pokeMachineCodeOptions (TO.machineCodeOptions hOpts) =<< machineCodeOptions opts
pokeMachineCodeOptions :: TO.MachineCodeOptions -> MCTargetOptions -> IO ()
pokeMachineCodeOptions hOpts (MCTargetOptions cOpts) =
mapM_ (\(c, ha) -> FFI.setMCTargetOptionFlag cOpts c =<< encodeM (ha hOpts)) [
(FFI.mcTargetOptionFlagMCRelaxAll, TO.relaxAll),
(FFI.mcTargetOptionFlagMCNoExecStack, TO.noExecutableStack),
(FFI.mcTargetOptionFlagMCFatalWarnings, TO.fatalWarnings),
(FFI.mcTargetOptionFlagMCNoWarn, TO.noWarnings),
(FFI.mcTargetOptionFlagMCNoDeprecatedWarn, TO.noDeprecatedWarning),
(FFI.mcTargetOptionFlagMCSaveTempLabels, TO.saveTemporaryLabels),
(FFI.mcTargetOptionFlagMCUseDwarfDirectory, TO.useDwarfDirectory),
(FFI.mcTargetOptionFlagMCIncrementalLinkerCompatible, TO.incrementalLinkerCompatible),
(FFI.mcTargetOptionFlagShowMCEncoding, TO.showMachineCodeEncoding),
(FFI.mcTargetOptionFlagShowMCInst, TO.showMachineCodeInstructions),
(FFI.mcTargetOptionFlagAsmVerbose, TO.verboseAssembly),
(FFI.mcTargetOptionFlagPreserveAsmComments, TO.preserveComentsInAssembly)
]
-- | get all target options
peekTargetOptions :: TargetOptions -> IO TO.Options
peekTargetOptions opts@(TargetOptions tOpts) = do
let gof = decodeM <=< FFI.getTargetOptionsFlag tOpts
unsafeFloatingPointMath
<- gof FFI.targetOptionFlagUnsafeFPMath
noInfinitiesFloatingPointMath
<- gof FFI.targetOptionFlagNoInfsFPMath
noNaNsFloatingPointMath
<- gof FFI.targetOptionFlagNoNaNsFPMath
noTrappingFloatingPointMath
<- gof FFI.targetOptionFlagNoTrappingFPMath
noSignedZeroesFloatingPointMath
<- gof FFI.targetOptionFlagNoSignedZerosFPMath
honorSignDependentRoundingFloatingPointMathOption
<- gof FFI.targetOptionFlagHonorSignDependentRoundingFPMathOption
noZerosInBSS
<- gof FFI.targetOptionFlagNoZerosInBSS
guaranteedTailCallOptimization
<- gof FFI.targetOptionFlagGuaranteedTailCallOpt
stackSymbolOrdering
<- gof FFI.targetOptionFlagStackSymbolOrdering
enableFastInstructionSelection
<- gof FFI.targetOptionFlagEnableFastISel
useInitArray
<- gof FFI.targetOptionFlagUseInitArray
disableIntegratedAssembler
<- gof FFI.targetOptionFlagDisableIntegratedAS
compressDebugSections <- decodeM =<< FFI.getCompressDebugSections tOpts
relaxELFRelocations
<- gof FFI.targetOptionFlagRelaxELFRelocations
functionSections
<- gof FFI.targetOptionFlagFunctionSections
dataSections
<- gof FFI.targetOptionFlagDataSections
uniqueSectionNames
<- gof FFI.targetOptionFlagUniqueSectionNames
trapUnreachable
<- gof FFI.targetOptionFlagTrapUnreachable
emulatedThreadLocalStorage
<- gof FFI.targetOptionFlagEmulatedTLS
enableInterProceduralRegisterAllocation
<- gof FFI.targetOptionFlagEnableIPRA
stackAlignmentOverride <- decodeM =<< FFI.getStackAlignmentOverride tOpts
floatABIType <- decodeM =<< FFI.getFloatABIType tOpts
allowFloatingPointOperationFusion <- decodeM =<< FFI.getAllowFPOpFusion tOpts
threadModel <- decodeM =<< FFI.getThreadModel tOpts
eabiVersion <- decodeM =<< FFI.getEABIVersion tOpts
debuggerTuning <- decodeM =<< FFI.getDebuggerTuning tOpts
floatingPointDenormalMode <- decodeM =<< FFI.getFPDenormalMode tOpts
exceptionModel <- decodeM =<< FFI.getExceptionModel tOpts
machineCodeOptions <- peekMachineCodeOptions =<< machineCodeOptions opts
return TO.Options { .. }
-- | get all machine code options
peekMachineCodeOptions :: MCTargetOptions -> IO TO.MachineCodeOptions
peekMachineCodeOptions (MCTargetOptions tOpts) = do
let gof = decodeM <=< FFI.getMCTargetOptionsFlag tOpts
relaxAll
<- gof FFI.mcTargetOptionFlagMCRelaxAll
noExecutableStack
<- gof FFI.mcTargetOptionFlagMCNoExecStack
fatalWarnings
<- gof FFI.mcTargetOptionFlagMCFatalWarnings
noWarnings
<- gof FFI.mcTargetOptionFlagMCNoWarn
noDeprecatedWarning
<- gof FFI.mcTargetOptionFlagMCNoDeprecatedWarn
saveTemporaryLabels
<- gof FFI.mcTargetOptionFlagMCSaveTempLabels
useDwarfDirectory
<- gof FFI.mcTargetOptionFlagMCUseDwarfDirectory
incrementalLinkerCompatible
<- gof FFI.mcTargetOptionFlagMCIncrementalLinkerCompatible
showMachineCodeEncoding
<- gof FFI.mcTargetOptionFlagShowMCEncoding
showMachineCodeInstructions
<- gof FFI.mcTargetOptionFlagShowMCInst
verboseAssembly
<- gof FFI.mcTargetOptionFlagAsmVerbose
preserveComentsInAssembly
<- gof FFI.mcTargetOptionFlagPreserveAsmComments
return TO.MachineCodeOptions { .. }
-- | <http://llvm.org/doxygen/classllvm_1_1TargetMachine.html>
newtype TargetMachine = TargetMachine (Ptr FFI.TargetMachine)
-- | bracket creation and destruction of a 'TargetMachine'
withTargetMachine ::
Target
-> ShortByteString -- ^ triple
-> ByteString -- ^ cpu
-> Map CPUFeature Bool -- ^ features
-> TargetOptions
-> Reloc.Model
-> CodeModel.Model
-> CodeGenOpt.Level
-> (TargetMachine -> IO a)
-> IO a
withTargetMachine
(Target target)
triple
cpu
features
(TargetOptions targetOptions)
relocModel
codeModel
codeGenOptLevel = runAnyContT $ do
triple <- encodeM triple
cpu <- encodeM cpu
features <- encodeM features
relocModel <- encodeM relocModel
codeModel <- encodeM codeModel
codeGenOptLevel <- encodeM codeGenOptLevel
anyContToM $ bracket (
FFI.createTargetMachine
target
triple
cpu
features
targetOptions
relocModel
codeModel
codeGenOptLevel
)
FFI.disposeTargetMachine
. (. TargetMachine)
targetMachineOptions :: TargetMachine -> IO TargetOptions
targetMachineOptions (TargetMachine tm) = TargetOptions <$> FFI.targetMachineOptions tm
machineCodeOptions :: TargetOptions -> IO MCTargetOptions
machineCodeOptions (TargetOptions to) = MCTargetOptions <$> FFI.machineCodeOptions to
-- | <http://llvm.org/doxygen/classllvm_1_1TargetLowering.html>
newtype TargetLowering = TargetLowering (Ptr FFI.TargetLowering)
-- | get the 'TargetLowering' of a 'TargetMachine'
getTargetLowering :: TargetMachine -> IO TargetLowering
getTargetLowering (TargetMachine _) = TargetLowering <$> error "FIXME: getTargetLowering" -- FFI.getTargetLowering tm
-- | Initialize the native target. This function is called automatically in these Haskell bindings
-- when creating an 'LLVM.ExecutionEngine.ExecutionEngine' which will require it, and so it should
-- not be necessary to call it separately.
initializeNativeTarget :: IO ()
initializeNativeTarget = do
failure <- decodeM =<< liftIO FFI.initializeNativeTarget
when failure $ fail "native target initialization failed"
-- | the target triple corresponding to the target machine
getTargetMachineTriple :: TargetMachine -> IO ShortByteString
getTargetMachineTriple (TargetMachine m) = decodeM =<< FFI.getTargetMachineTriple m
-- | the default target triple that LLVM has been configured to produce code for
getDefaultTargetTriple :: IO ShortByteString
getDefaultTargetTriple = decodeM =<< FFI.getDefaultTargetTriple
-- | a target triple suitable for loading code into the current process
getProcessTargetTriple :: IO ShortByteString
getProcessTargetTriple = decodeM =<< FFI.getProcessTargetTriple
-- | the LLVM name for the host CPU
getHostCPUName :: IO ByteString
getHostCPUName = decodeM FFI.getHostCPUName
-- | a space-separated list of LLVM feature names supported by the host CPU
getHostCPUFeatures :: IO (Map CPUFeature Bool)
getHostCPUFeatures =
decodeM =<< FFI.getHostCPUFeatures
-- | 'DataLayout' to use for the given 'TargetMachine'
getTargetMachineDataLayout :: TargetMachine -> IO DataLayout
getTargetMachineDataLayout (TargetMachine m) = do
dlString <- decodeM =<< FFI.getTargetMachineDataLayout m
let Right (Just dl) = runExcept . parseDataLayout BigEndian $ dlString
return dl
-- | Initialize all targets so they can be found by 'lookupTarget'
initializeAllTargets :: IO ()
initializeAllTargets = FFI.initializeAllTargets
-- | Bracket creation and destruction of a 'TargetMachine' configured for the host.
--
-- This function infers and fills the properties of the host machine
-- (architecture, CPU type, operating system etc.) to construct
-- a 'TargetMachine' value, but other parameters of 'TargetMachine' (the
-- code model, relocation model, and optimization level) have to be
-- provided by the user. For instance, for the JIT-compiled code that you
-- want to dynamically load you probably want to use the 'Reloc.PIC'
-- relocation model.
withHostTargetMachine
:: Reloc.Model
-> CodeModel.Model
-> CodeGenOpt.Level
-> (TargetMachine -> IO a) -> IO a
withHostTargetMachine relocModel codeModel codeGenOpt f = do
initializeAllTargets
triple <- getProcessTargetTriple
cpu <- getHostCPUName
features <- getHostCPUFeatures
(target, _) <- lookupTarget Nothing triple
withTargetOptions $ \options ->
withTargetMachine target triple cpu features options relocModel codeModel codeGenOpt f
-- | Like 'withHostTargetMachine', but assumes the default values for the
-- relocation model, code model, and optimization level ('Reloc.Default',
-- 'CodeModel.Default', 'CodeGenOpt.Default' respectively).
--
-- Note that the 'Reloc.Default' relocation model __is not__ suitable for
-- JIT compilation; use 'withHostTargetMachine' and 'Reloc.PIC' instead.
withHostTargetMachineDefault :: (TargetMachine -> IO a) -> IO a
withHostTargetMachineDefault f = withHostTargetMachine Reloc.Default CodeModel.Default CodeGenOpt.Default f
-- | <http://llvm.org/docs/doxygen/html/classllvm_1_1TargetLibraryInfo.html>
newtype TargetLibraryInfo = TargetLibraryInfo (Ptr FFI.TargetLibraryInfo)
-- | Look up a 'LibraryFunction' by its standard name
getLibraryFunction :: TargetLibraryInfo -> ShortByteString -> IO (Maybe LibraryFunction)
getLibraryFunction (TargetLibraryInfo f) name = runAnyContT' return $ do
libFuncP <- alloca :: AnyContT IO (Ptr FFI.LibFunc)
name <- (encodeM name :: AnyContT IO CString)
r <- decodeM =<< (liftIO $ FFI.getLibFunc f name libFuncP)
forM (if r then Just libFuncP else Nothing) $ decodeM <=< peek
-- | Get a the current name to be emitted for a 'LibraryFunction'
getLibraryFunctionName :: TargetLibraryInfo -> LibraryFunction -> IO ShortByteString
getLibraryFunctionName (TargetLibraryInfo f) l = runAnyContT' return $ do
l <- encodeM l
decodeM $ FFI.libFuncGetName f l
-- | Set the name of the function on the target platform that corresponds to funcName
setLibraryFunctionAvailableWithName ::
TargetLibraryInfo
-> LibraryFunction
-> ShortByteString -- ^ The function name to be emitted
-> IO ()
setLibraryFunctionAvailableWithName (TargetLibraryInfo f) libraryFunction name = runAnyContT' return $ do
name <- encodeM name
libraryFunction <- encodeM libraryFunction
liftIO $ FFI.libFuncSetAvailableWithName f libraryFunction name
-- | look up information about the library functions available on a given platform
withTargetLibraryInfo ::
ShortByteString -- ^ triple
-> (TargetLibraryInfo -> IO a)
-> IO a
withTargetLibraryInfo triple f = runAnyContT' return $ do
triple <- encodeM triple
liftIO $ bracket (FFI.createTargetLibraryInfo triple) FFI.disposeTargetLibraryInfo (f . TargetLibraryInfo)