Skip to content

Commit 9721cbf

Browse files
authored
Merge pull request #1046 from yashssh/npm-numba
Add basic infra required to move Numba to NewPassManager
2 parents cb8baa4 + 69c867c commit 9721cbf

File tree

14 files changed

+1191
-33
lines changed

14 files changed

+1191
-33
lines changed

docs/source/user-guide/binding/optimization-passes.rst

Lines changed: 189 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,176 @@ Optimization passes
44

55
.. currentmodule:: llvmlite.binding
66

7-
LLVM gives you the opportunity to fine-tune optimization passes.
8-
Optimization passes are managed by a pass manager. There are 2
9-
kinds of pass managers:
7+
LLVM gives you the opportunity to fine-tune optimization passes. Optimization
8+
passes are managed by a pass manager. There are two kinds of pass managers:
109

1110
* :class:`FunctionPassManager`, for optimizations that work on
1211
single functions.
1312

1413
* :class:`ModulePassManager`, for optimizations that work on
1514
whole modules.
1615

16+
llvmlite provides bindings for LLVM's *New* and *Legacy* pass managers, which
17+
have slightly different APIs and behaviour. The differences between them and the
18+
motivations for the New Pass Manager are outlined in the `LLVM Blog post on the
19+
New Pass Manager
20+
<https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager/>`_.
21+
22+
In a future version of llvmlite, likely coinciding with a minimum LLVM version
23+
requirement of 17, support for the Legacy Pass Manager will be removed. It is
24+
recommended that new code using llvmlite uses the New Pass Manager, and existing
25+
code using the Legacy Pass Manager be updated to use the New Pass Manager.
26+
27+
28+
New Pass Manager APIs
29+
=====================
30+
31+
To manage the optimization attributes we first need to instantiate a
32+
:class:`PipelineTuningOptions` instance:
33+
34+
.. class:: PipelineTuningOptions(speed_level=2, size_level=0)
35+
36+
Creates a new PipelineTuningOptions object.
37+
38+
The following writable attributes are available, whose default values depend
39+
on the initial setting of the speed and size optimization levels:
40+
41+
* .. attribute:: loop_interleaving
42+
43+
Enable loop interleaving.
44+
45+
* .. attribute:: loop_vectorization
46+
47+
Enable loop vectorization.
48+
49+
* .. attribute:: slp_vectorization
50+
51+
Enable SLP vectorization, which uses a different algorithm to
52+
loop vectorization. Both may be enabled at the same time.
53+
54+
* .. attribute:: loop_unrolling
55+
56+
Enable loop unrolling.
57+
58+
* .. attribute:: speed_level
59+
60+
The level of optimization for speed, as an integer between 0 and 3.
61+
62+
* .. attribute:: size_level
63+
64+
The level of optimization for size, as an integer between 0 and 2.
65+
66+
.. FIXME: Available from llvm16
67+
.. * .. attribute:: inlining_threshold
68+
69+
.. The integer threshold for inlining one function into
70+
.. another. The higher the number, the more likely that
71+
.. inlining will occur. This attribute is write-only.
72+
73+
74+
We also need a :class:`PassBuilder` object to manage the respective function
75+
and module pass managers:
76+
77+
.. class:: PassBuilder(target_machine, pipeline_tuning_options)
78+
79+
A pass builder that uses the given :class:`TargetMachine` and
80+
:class:`PipelineTuningOptions` instances.
81+
82+
.. method:: getModulePassManager()
83+
84+
Return a populated :class:`ModulePassManager` object based on PTO settings.
85+
86+
.. method:: getFunctionPassManager()
87+
88+
Return a populated :class:`FunctionPassManager` object based on PTO
89+
settings.
90+
91+
92+
The :class:`ModulePassManager` and :class:`FunctionPassManager` classes
93+
implement the module and function pass managers:
94+
95+
.. class:: ModulePassManager()
96+
97+
A pass manager for running optimization passes on an LLVM module.
98+
99+
.. method:: add_verifier()
100+
101+
Add the `Module Verifier
102+
<https://llvm.org/docs/Passes.html#verify-module-verifier>`_ pass.
103+
104+
.. method:: run(module, passbuilder)
105+
106+
Run optimization passes on *module*, a :class:`ModuleRef` instance.
107+
108+
109+
.. class:: FunctionPassManager()
110+
111+
A pass manager for running optimization passes on an LLVM function.
112+
113+
.. method:: run(function, passbuilder)
114+
115+
Run optimization passes on *function*, a :class:`ValueRef` instance.
116+
117+
118+
These can be created with passes populated by using the
119+
:meth:`PassBuilder.getModulePassManager` and
120+
:meth:`PassBuilder.getFunctionPassManager` methods, or they can be instantiated
121+
unpopulated, then passes can be added using the ``add_*`` methods.
122+
123+
To instantiate the unpopulated instances, use:
124+
125+
.. function:: create_new_module_pass_manager()
126+
127+
Create an unpopulated :class:`ModulePassManager` instance.
128+
129+
and
130+
131+
.. function:: create_new_function_pass_manager()
132+
133+
Create an unpopulated :class:`FunctionPassManager` instance.
134+
135+
136+
The ``add_*`` methods supported by both pass manager classes are:
137+
138+
.. currentmodule:: None
139+
140+
.. method:: add_aa_eval_pass()
141+
142+
Add the `Exhaustive Alias Analysis Precision Evaluator
143+
<https://llvm.org/docs/Passes.html#aa-eval-exhaustive-alias-analysis-precision-evaluator>`_
144+
pass.
145+
146+
.. method:: add_loop_unroll_pass()
147+
148+
Add the `Loop Unroll
149+
<https://llvm.org/docs/Passes.html#loop-unroll-unroll-loops>`_ pass.
150+
151+
.. method:: add_loop_rotate_pass()
152+
153+
Add the `Loop Rotate
154+
<https://llvm.org/docs/Passes.html#loop-rotate-rotate-loops>`_ pass.
155+
156+
.. method:: add_instruction_combine_pass()
157+
158+
Add the `Combine Redundant Instructions
159+
<https://llvm.org/docs/Passes.html#instcombine-combine-redundant-instructions>`_
160+
pass.
161+
162+
.. method:: add_jump_threading_pass()
163+
164+
Add the `Jump Threading
165+
<https://llvm.org/docs/Passes.html#jump-threading-jump-threading>`_ pass.
166+
167+
.. method:: add_simplify_cfg_pass()
168+
169+
Add the `Simplify CFG
170+
<https://llvm.org/docs/Passes.html#simplifycfg-simplify-the-cfg>`_ pass.
171+
172+
.. currentmodule:: llvmlite.binding
173+
174+
Legacy Pass Manager APIs
175+
========================
176+
17177
To instantiate either of these pass managers, you first need to
18178
create and configure a :class:`PassManagerBuilder`.
19179

@@ -24,42 +184,42 @@ create and configure a :class:`PassManagerBuilder`.
24184

25185
The ``populate`` method is available:
26186

27-
.. method:: populate(pm)
187+
.. method:: populate(pm)
28188

29-
Populate the pass manager *pm* with the optimization passes
30-
configured in this pass manager builder.
189+
Populate the pass manager *pm* with the optimization passes
190+
configured in this pass manager builder.
31191

32-
The following writable attributes are available:
192+
The following writable attributes are available:
33193

34-
* .. attribute:: disable_unroll_loops
194+
* .. attribute:: disable_unroll_loops
35195

36-
If ``True``, disable loop unrolling.
196+
If ``True``, disable loop unrolling.
37197

38-
* .. attribute:: inlining_threshold
198+
* .. attribute:: inlining_threshold
39199

40-
The integer threshold for inlining one function into
41-
another. The higher the number, the more likely that
42-
inlining will occur. This attribute is write-only.
200+
The integer threshold for inlining one function into
201+
another. The higher the number, the more likely that
202+
inlining will occur. This attribute is write-only.
43203

44-
* .. attribute:: loop_vectorize
204+
* .. attribute:: loop_vectorize
45205

46-
If ``True``, allow vectorizing loops.
206+
If ``True``, allow vectorizing loops.
47207

48-
* .. attribute:: opt_level
208+
* .. attribute:: opt_level
49209

50-
The general optimization level, as an integer between 0
51-
and 3.
210+
The general optimization level, as an integer between 0
211+
and 3.
52212

53-
* .. attribute:: size_level
213+
* .. attribute:: size_level
54214

55-
Whether and how much to optimize for size, as an integer
56-
between 0 and 2.
215+
Whether and how much to optimize for size, as an integer
216+
between 0 and 2.
57217

58-
* .. attribute:: slp_vectorize
218+
* .. attribute:: slp_vectorize
59219

60-
If ``True``, enable the SLP vectorizer, which uses a
61-
different algorithm than the loop vectorizer. Both may
62-
be enabled at the same time.
220+
If ``True``, enable the SLP vectorizer, which uses a
221+
different algorithm than the loop vectorizer. Both may
222+
be enabled at the same time.
63223

64224

65225
.. class:: PassManager
@@ -142,13 +302,15 @@ create and configure a :class:`PassManagerBuilder`.
142302
See `instnamer pass documentation <http://llvm.org/docs/Passes.html#instnamer-assign-names-to-anonymous-instructions>`_.
143303

144304
.. class:: ModulePassManager()
305+
:no-index:
145306

146307
Create a new pass manager to run optimization passes on a
147308
module.
148309

149310
The ``run`` method is available:
150311

151312
.. method:: run(module)
313+
:no-index:
152314

153315
Run optimization passes on the
154316
*module*, a :class:`ModuleRef` instance.
@@ -157,6 +319,7 @@ create and configure a :class:`PassManagerBuilder`.
157319
to the module. Otherwise returns ``False``.
158320

159321
.. class:: FunctionPassManager(module)
322+
:no-index:
160323

161324
Create a new pass manager to run optimization passes on a
162325
function of the given *module*, a :class:`ModuleRef` instance.
@@ -172,6 +335,7 @@ create and configure a :class:`PassManagerBuilder`.
172335
Run all the initializers of the optimization passes.
173336

174337
* .. method:: run(function)
338+
:no-index:
175339

176340
Run optimization passes on *function*, a
177341
:class:`ValueRef` instance.

examples/npm_passes.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
This example demonstrates how to use the new module pass manager to optimize a
3+
module using the loop unrolling and CFG simplification passes.
4+
"""
5+
6+
import faulthandler
7+
import llvmlite.binding as llvm
8+
9+
# Dump Python traceback in the event of a segfault
10+
faulthandler.enable()
11+
12+
# All are required to initialize LLVM
13+
llvm.initialize()
14+
llvm.initialize_native_target()
15+
llvm.initialize_native_asmprinter()
16+
17+
# Module to optimize
18+
strmod = """
19+
define i32 @foo3(i32* noalias nocapture readonly %src) {
20+
entry:
21+
br label %loop.header
22+
23+
loop.header:
24+
%iv = phi i64 [ 0, %entry ], [ %inc, %loop.latch ]
25+
%r1 = phi i32 [ 0, %entry ], [ %r3, %loop.latch ]
26+
%arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv
27+
%src_element = load i32, i32* %arrayidx, align 4
28+
%cmp = icmp eq i32 0, %src_element
29+
br i1 %cmp, label %loop.if, label %loop.latch
30+
31+
loop.if:
32+
%r2 = add i32 %r1, 1
33+
br label %loop.latch
34+
loop.latch:
35+
%r3 = phi i32 [%r1, %loop.header], [%r2, %loop.if]
36+
%inc = add nuw nsw i64 %iv, 1
37+
%exitcond = icmp eq i64 %inc, 9
38+
br i1 %exitcond, label %loop.end, label %loop.header
39+
loop.end:
40+
%r.lcssa = phi i32 [ %r3, %loop.latch ]
41+
ret i32 %r.lcssa
42+
}
43+
"""
44+
45+
46+
module = llvm.parse_assembly(strmod)
47+
48+
print("Module before optimization:\n")
49+
print(module)
50+
51+
# Set up the module pass manager used to run our optimization pipeline.
52+
# We create it unpopulated, and then add the loop unroll and simplify CFG
53+
# passes.
54+
pm = llvm.create_new_module_pass_manager()
55+
pm.add_loop_unroll_pass()
56+
pm.add_simplify_cfg_pass()
57+
58+
59+
# To run the pass manager, we need a pass builder object - we create pipeline
60+
# tuning options with no optimization, then use that to create a pass builder.
61+
target_machine = llvm.Target.from_default_triple().create_target_machine()
62+
pto = llvm.create_pipeline_tuning_options(speed_level=0)
63+
pb = llvm.create_pass_builder(target_machine, pto)
64+
65+
# Now we can run the pass manager on our module
66+
pm.run(module, pb)
67+
68+
69+
# We should observer a fully unrolled loop, and the function now consists of a
70+
# single basic block executing all the iterations of the loop in a straight
71+
# line.
72+
print("\nModule after optimization:\n")
73+
print(module)

0 commit comments

Comments
 (0)