{- LLVM does not export its functions @createStandardFunctionPasses@ and @createStandardModulePasses@ via its C interface and interfacing to C-C++ wrappers is not very portable. Thus we reimplement these functions from @opt.cpp@ and @StandardPasses.h@ in Haskell. However this way we risk inconsistencies between 'optimizeModule' and the @opt@ shell command. -} module LLVM.Util.Optimize(optimizeModule) where import LLVM.Core.Util(Module, withModule) import qualified LLVM.FFI.Core as FFI import qualified LLVM.FFI.Support as FFI import LLVM.FFI.Transforms.Scalar import Control.Exception (bracket) {- | Result tells whether the module was modified by any of the passes. -} optimizeModule :: Int -> Module -> IO Bool optimizeModule optLevel mdl = withModule mdl $ \ m -> {- Core.Util.createPassManager would provide a finalizer for us, but I think it is better here to immediately dispose the manager when we need it no longer. -} bracket FFI.createPassManager FFI.disposePassManager $ \ passes -> {- Note on LLVM-2.6 to 2.8 (at least): As far as I understand, if we do not set target data, then the optimizer will only perform machine independent optimizations. If we set target data (e.g. an empty layout string obtained from a module without 'target data' specification.) we risk that the optimizer switches to a wrong layout (e.g. to 64 bit pointers on a 32 bit machine for empty layout string) and thus generates corrupt code. Currently it seems to be safer to disable machine dependent optimization completely. http://llvm.org/bugs/show_bug.cgi?id=6394 -- Pass the module target data to the pass manager. target <- FFI.getDataLayout m >>= createTargetData addTargetData target passes -} {- opt.cpp does not use a FunctionPassManager for function optimization, but a module PassManager. Thus we do it the same way. I assume that we would need a FunctionPassManager only if we wanted to apply individual optimizations to functions. fPasses <- FFI.createFunctionPassManager mp -} bracket FFI.createPassManager FFI.disposePassManager $ \ fPasses -> do -- add module target data? -- tools/opt/opt.cpp: AddStandardCompilePasses addVerifierPass passes addOptimizationPasses passes fPasses optLevel {- if we wanted to do so, we could loop through all functions and optimize them. initializeFunctionPassManager fPasses runFunctionPassManager fPasses fcn -} functionsModified <- FFI.runPassManager fPasses m moduleModified <- FFI.runPassManager passes m return $ toEnum (fromIntegral moduleModified) || toEnum (fromIntegral functionsModified) -- tools/opt/opt.cpp: AddOptimizationPasses addOptimizationPasses :: FFI.PassManagerRef -> FFI.PassManagerRef -> Int -> IO () addOptimizationPasses passes fPasses optLevel = do createStandardFunctionPasses fPasses optLevel createStandardModulePasses passes optLevel True True (optLevel > 1) True True True createStandardFunctionPasses :: FFI.PassManagerRef -> Int -> IO () createStandardFunctionPasses fPasses optLevel = FFI.createStandardFunctionPasses fPasses (fromIntegral optLevel) -- llvm/Support/StandardPasses.h: createStandardModulePasses createStandardModulePasses :: FFI.PassManagerRef -> Int -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> IO () createStandardModulePasses passes optLevel optSize unitAtATime unrollLoops simplifyLibCalls haveExceptions inliningPass = FFI.createStandardModulePasses passes (fromIntegral optLevel) (f optSize) (f unitAtATime) (f unrollLoops) (f simplifyLibCalls) (f haveExceptions) (f (not inliningPass)) where f True = 1 f _ = 0 {- ToDo: Function that adds passes according to a list of opt-options. This would simplify to get consistent behaviour between opt and optimizeModule. -adce addAggressiveDCEPass -deadargelim addDeadArgEliminationPass -deadtypeelim addDeadTypeEliminationPass -dse addDeadStoreEliminationPass -functionattrs addFunctionAttrsPass -globalopt addGlobalOptimizerPass -indvars addIndVarSimplifyPass -instcombine addInstructionCombiningPass -ipsccp addIPSCCPPass -jump-threading addJumpThreadingPass -licm addLICMPass -loop-deletion addLoopDeletionPass -loop-rotate addLoopRotatePass -memcpyopt addMemCpyOptPass -prune-eh addPruneEHPass -reassociate addReassociatePass -scalarrepl addScalarReplAggregatesPass -sccp addSCCPPass -simplifycfg addCFGSimplificationPass -simplify-libcalls addSimplifyLibCallsPass -strip-dead-prototypes addStripDeadPrototypesPass -tailcallelim addTailCallEliminationPass -verify addVerifierPass -}