/
Optimize.hs
132 lines (112 loc) · 4.94 KB
/
Optimize.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{-
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.Target(addTargetData, createTargetData)
import LLVM.FFI.Transforms.IPO
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
-}