llvm-general-3.2.6.0: src/LLVM/General/Internal/PassManager.hs
{-# LANGUAGE
TemplateHaskell,
MultiParamTypeClasses
#-}
module LLVM.General.Internal.PassManager where
import qualified Language.Haskell.TH as TH
import Control.Exception
import Control.Monad hiding (forM_)
import Control.Monad.IO.Class
import Control.Applicative
import Control.Monad.AnyCont
import Data.Word
import Data.Foldable (forM_)
import Foreign.Ptr
import qualified LLVM.General.Internal.FFI.PassManager as FFI
import qualified LLVM.General.Internal.FFI.Transforms as FFI
import qualified LLVM.General.Internal.FFI.LLVMCTypes as FFI
import LLVM.General.Internal.Module
import LLVM.General.Internal.Target
import LLVM.General.Internal.Coding
import LLVM.General.Internal.DataLayout
import LLVM.General.Transforms
import LLVM.General.AST.DataLayout
-- | <http://llvm.org/doxygen/classllvm_1_1PassManager.html>
-- Note: a PassManager does substantive behind-the-scenes work, arranging for the
-- results of various analyses to be available as needed by transform passes, shared
-- as possible.
newtype PassManager = PassManager (Ptr FFI.PassManager)
-- | There are different ways to get a 'PassManager'. This type embodies them.
data PassSetSpec
-- | a 'PassSetSpec' is a lower-level, detailed specification of a set of passes. It
-- allows fine-grained control of what passes are to be run when, and the specification
-- of passes not available through 'CuratedPassSetSpec'.
= PassSetSpec {
transforms :: [Pass],
dataLayout :: Maybe DataLayout,
targetLibraryInfo :: Maybe TargetLibraryInfo,
targetLowering :: Maybe TargetLowering
}
-- | This type is a high-level specification of a set of passes. It uses the same
-- collection of passes chosen by the LLVM team in the command line tool 'opt'. The fields
-- of this spec are much like typical compiler command-line flags - e.g. -O\<n\>, etc.
| CuratedPassSetSpec {
optLevel :: Maybe Word,
sizeLevel :: Maybe Word,
unitAtATime :: Maybe Bool,
simplifyLibCalls :: Maybe Bool,
useInlinerWithThreshold :: Maybe Word
}
-- | Helper to make a curated 'PassSetSpec'
defaultCuratedPassSetSpec = CuratedPassSetSpec {
optLevel = Nothing,
sizeLevel = Nothing,
unitAtATime = Nothing,
simplifyLibCalls = Nothing,
useInlinerWithThreshold = Nothing
}
-- | an empty 'PassSetSpec'
defaultPassSetSpec = PassSetSpec {
transforms = [],
dataLayout = Nothing,
targetLibraryInfo = Nothing,
targetLowering = Nothing
}
instance (Monad m, MonadAnyCont IO m) => EncodeM m GCOVVersion FFI.LLVMBool where
encodeM (GCOVVersion "402*") = encodeM True
encodeM (GCOVVersion "404*") = encodeM False
encodeM s = fail $ "unsupported GCOVVersion: "++ show s ++ ". llvm-3.2 supports only \"402*\" and \"404*\""
createPassManager :: PassSetSpec -> IO (Ptr FFI.PassManager)
createPassManager pss = flip runAnyContT return $ do
pm <- liftIO $ FFI.createPassManager
case pss of
s@CuratedPassSetSpec {} -> liftIO $ do
bracket FFI.passManagerBuilderCreate FFI.passManagerBuilderDispose $ \b -> do
let handleOption g m = forM_ (m s) (g b <=< encodeM)
handleOption FFI.passManagerBuilderSetOptLevel optLevel
handleOption FFI.passManagerBuilderSetSizeLevel sizeLevel
handleOption FFI.passManagerBuilderSetDisableUnitAtATime (liftM not . unitAtATime)
handleOption FFI.passManagerBuilderSetDisableSimplifyLibCalls (liftM not . simplifyLibCalls)
handleOption FFI.passManagerBuilderUseInlinerWithThreshold useInlinerWithThreshold
FFI.passManagerBuilderPopulateModulePassManager b pm
PassSetSpec ps dl tli tl' -> do
let tl = maybe nullPtr (\(TargetLowering tl) -> tl) tl'
forM_ tli $ \(TargetLibraryInfo tli) -> do
liftIO $ FFI.addTargetLibraryInfoPass pm tli
forM_ dl $ \dl -> liftIO $ withFFIDataLayout dl $ FFI.addDataLayoutPass pm
forM_ ps $ \p -> $(
do
TH.TyConI (TH.DataD _ _ _ cons _) <- TH.reify ''Pass
TH.caseE [| p |] $ flip map cons $ \con -> do
let
(n, fns) = case con of
TH.RecC n fs -> (n, [ TH.nameBase fn | (fn, _, _) <- fs ])
TH.NormalC n [] -> (n, [])
actions =
[ TH.bindS (TH.varP . TH.mkName $ fn) [| encodeM $(TH.dyn fn) |] | fn <- fns ]
++ [
TH.noBindS [|
liftIO $(
foldl1 TH.appE
(map TH.dyn $
["FFI.add" ++ TH.nameBase n ++ "Pass", "pm"]
++ ["tl" | FFI.needsTargetLowering (TH.nameBase n)]
++ fns)
)
|]
]
TH.match (TH.conP n $ map (TH.varP . TH.mkName) fns) (TH.normalB (TH.doE actions)) []
)
return pm
-- | bracket the creation of a 'PassManager'
withPassManager :: PassSetSpec -> (PassManager -> IO a) -> IO a
withPassManager s = bracket (createPassManager s) FFI.disposePassManager . (. PassManager)
-- | run the passes in a 'PassManager' on a 'Module', modifying the 'Module'.
runPassManager :: PassManager -> Module -> IO Bool
runPassManager (PassManager p) (Module m) = toEnum . fromIntegral <$> FFI.runPassManager p m