Skip to content

Commit 4b260e8

Browse files
committed
Port refprune to NewPassManager
Based on the changes introduced in numba#1042 by @modiking
1 parent 78ebf9b commit 4b260e8

4 files changed

Lines changed: 207 additions & 68 deletions

File tree

ffi/custom_passes.cpp

Lines changed: 157 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,22 @@
2626
using namespace llvm;
2727

2828
namespace llvm {
29-
void initializeRefNormalizePassPass(PassRegistry &Registry);
30-
void initializeRefPrunePassPass(PassRegistry &Registry);
29+
void initializeRefNormalizeLegacyPassPass(PassRegistry &Registry);
30+
void initializeRefPruneLegacyPassPass(PassRegistry &Registry);
3131
} // namespace llvm
3232

33+
namespace llvm {
34+
struct OpaqueModulePassManager;
35+
typedef OpaqueModulePassManager *LLVMModulePassManagerRef;
36+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ModulePassManager, LLVMModulePassManagerRef)
37+
38+
struct OpaqueFunctionPassManager;
39+
typedef OpaqueFunctionPassManager *LLVMFunctionPassManagerRef;
40+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(FunctionPassManager,
41+
LLVMFunctionPassManagerRef)
42+
} // namespace llvm
43+
44+
namespace {
3345
/**
3446
* Checks if a call instruction is an incref
3547
*
@@ -104,13 +116,9 @@ template <class Tstack> struct raiiStack {
104116
* A FunctionPass to reorder incref/decref instructions such that decrefs occur
105117
* logically after increfs. This is a pre-requisite pass to the pruner passes.
106118
*/
107-
struct RefNormalizePass : public FunctionPass {
108-
static char ID;
109-
RefNormalizePass() : FunctionPass(ID) {
110-
initializeRefNormalizePassPass(*PassRegistry::getPassRegistry());
111-
}
119+
struct RefNormalize {
112120

113-
bool runOnFunction(Function &F) override {
121+
bool runOnFunction(Function &F) {
114122
bool mutated = false;
115123
// For each basic block in F
116124
for (BasicBlock &bb : F) {
@@ -158,7 +166,16 @@ struct RefNormalizePass : public FunctionPass {
158166
}
159167
};
160168

161-
struct RefPrunePass : public FunctionPass {
169+
typedef enum {
170+
None = 0b0000,
171+
PerBasicBlock = 0b0001,
172+
Diamond = 0b0010,
173+
Fanout = 0b0100,
174+
FanoutRaise = 0b1000,
175+
All = PerBasicBlock | Diamond | Fanout | FanoutRaise
176+
} Subpasses;
177+
178+
struct RefPrune {
162179
static char ID;
163180
static size_t stats_per_bb;
164181
static size_t stats_diamond;
@@ -175,25 +192,21 @@ struct RefPrunePass : public FunctionPass {
175192
/**
176193
* Enum for setting which subpasses to run, there is no interdependence.
177194
*/
178-
enum Subpasses {
179-
None = 0b0000,
180-
PerBasicBlock = 0b0001,
181-
Diamond = 0b0010,
182-
Fanout = 0b0100,
183-
FanoutRaise = 0b1000,
184-
All = PerBasicBlock | Diamond | Fanout | FanoutRaise
185-
} flags;
186195

187-
RefPrunePass(Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
188-
: FunctionPass(ID), flags(flags), subgraph_limit(subgraph_limit) {
189-
initializeRefPrunePassPass(*PassRegistry::getPassRegistry());
190-
}
196+
Subpasses flags;
197+
198+
DominatorTree &DT;
199+
PostDominatorTree &PDT;
200+
201+
RefPrune(DominatorTree &DT, PostDominatorTree &PDT,
202+
Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
203+
: DT(DT), PDT(PDT), flags(flags), subgraph_limit(subgraph_limit) {}
191204

192205
bool isSubpassEnabledFor(Subpasses expected) {
193206
return (flags & expected) == expected;
194207
}
195208

196-
bool runOnFunction(Function &F) override {
209+
bool runOnFunction(Function &F) {
197210
// state for LLVM function pass mutated IR
198211
bool mutated = false;
199212

@@ -361,11 +374,6 @@ struct RefPrunePass : public FunctionPass {
361374
*/
362375
bool runDiamondPrune(Function &F) {
363376
bool mutated = false;
364-
// gets the dominator tree
365-
auto &domtree = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
366-
// gets the post-dominator tree
367-
auto &postdomtree =
368-
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
369377

370378
// Find all increfs and decrefs in the Function and store them in
371379
// incref_list and decref_list respectively.
@@ -394,8 +402,8 @@ struct RefPrunePass : public FunctionPass {
394402
continue;
395403

396404
// incref DOM decref && decref POSTDOM incref
397-
if (domtree.dominates(incref, decref) &&
398-
postdomtree.dominates(decref, incref)) {
405+
if (DT.dominates(incref, decref) &&
406+
PDT.dominates(decref, incref)) {
399407
// check that the decref cannot be executed multiple times
400408
SmallBBSet tail_nodes;
401409
tail_nodes.insert(decref->getParent());
@@ -1028,14 +1036,6 @@ struct RefPrunePass : public FunctionPass {
10281036
return NULL;
10291037
}
10301038

1031-
/**
1032-
* getAnalysisUsage() LLVM plumbing for the pass
1033-
*/
1034-
void getAnalysisUsage(AnalysisUsage &Info) const override {
1035-
Info.addRequired<DominatorTreeWrapperPass>();
1036-
Info.addRequired<PostDominatorTreeWrapperPass>();
1037-
}
1038-
10391039
/**
10401040
* Checks if the first argument to the supplied call_inst is NULL and
10411041
* returns true if so, false otherwise.
@@ -1163,34 +1163,128 @@ struct RefPrunePass : public FunctionPass {
11631163
}
11641164
}
11651165
}
1166-
}; // end of struct RefPrunePass
1166+
}; // end of struct RefPrune
1167+
1168+
} // namespace
1169+
1170+
class RefPrunePass : public PassInfoMixin<RefPrunePass> {
1171+
1172+
public:
1173+
Subpasses flags;
1174+
size_t subgraph_limit;
1175+
RefPrunePass(Subpasses flags = Subpasses::All, size_t subgraph_limit = -1)
1176+
: flags(flags), subgraph_limit(subgraph_limit) {}
1177+
1178+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
1179+
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
1180+
auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
1181+
if (RefPrune(DT, PDT, flags, subgraph_limit).runOnFunction(F)) {
1182+
return PreservedAnalyses::none();
1183+
}
1184+
1185+
return PreservedAnalyses::all();
1186+
}
1187+
};
11671188

1168-
char RefNormalizePass::ID = 0;
1169-
char RefPrunePass::ID = 0;
1189+
class RefNormalizePass : public PassInfoMixin<RefNormalizePass> {
11701190

1171-
size_t RefPrunePass::stats_per_bb = 0;
1172-
size_t RefPrunePass::stats_diamond = 0;
1173-
size_t RefPrunePass::stats_fanout = 0;
1174-
size_t RefPrunePass::stats_fanout_raise = 0;
1191+
public:
1192+
RefNormalizePass() = default;
11751193

1176-
INITIALIZE_PASS(RefNormalizePass, "nrtrefnormalizepass", "Normalize NRT refops",
1177-
false, false)
1194+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
1195+
RefNormalize().runOnFunction(F);
11781196

1179-
INITIALIZE_PASS_BEGIN(RefPrunePass, "nrtrefprunepass", "Prune NRT refops",
1180-
false, false)
1197+
return PreservedAnalyses::all();
1198+
}
1199+
};
1200+
1201+
class RefNormalizeLegacyPass : public FunctionPass {
1202+
public:
1203+
static char ID;
1204+
RefNormalizeLegacyPass() : FunctionPass(ID) {
1205+
initializeRefNormalizeLegacyPassPass(*PassRegistry::getPassRegistry());
1206+
}
1207+
1208+
bool runOnFunction(Function &F) override {
1209+
return RefNormalize().runOnFunction(F);
1210+
};
1211+
};
1212+
1213+
class RefPruneLegacyPass : public FunctionPass {
1214+
1215+
public:
1216+
static char ID; // Pass identification, replacement for typeid
1217+
// The maximum number of nodes that the fanout pruners will look at.
1218+
size_t subgraph_limit;
1219+
Subpasses flags;
1220+
RefPruneLegacyPass(Subpasses flags = Subpasses::All,
1221+
size_t subgraph_limit = -1)
1222+
: FunctionPass(ID), flags(flags), subgraph_limit(subgraph_limit) {
1223+
initializeRefPruneLegacyPassPass(*PassRegistry::getPassRegistry());
1224+
}
1225+
1226+
bool runOnFunction(Function &F) override {
1227+
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1228+
1229+
auto &PDT =
1230+
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
1231+
1232+
return RefPrune(DT, PDT, flags, subgraph_limit).runOnFunction(F);
1233+
};
1234+
1235+
/**
1236+
* getAnalysisUsage() LLVM plumbing for the pass
1237+
*/
1238+
void getAnalysisUsage(AnalysisUsage &Info) const override {
1239+
Info.addRequired<DominatorTreeWrapperPass>();
1240+
Info.addRequired<PostDominatorTreeWrapperPass>();
1241+
}
1242+
};
1243+
1244+
char RefNormalizeLegacyPass::ID = 0;
1245+
char RefPruneLegacyPass::ID = 0;
1246+
1247+
size_t RefPrune::stats_per_bb = 0;
1248+
size_t RefPrune::stats_diamond = 0;
1249+
size_t RefPrune::stats_fanout = 0;
1250+
size_t RefPrune::stats_fanout_raise = 0;
1251+
1252+
INITIALIZE_PASS(RefNormalizeLegacyPass, "nrtRefNormalize",
1253+
"Normalize NRT refops", false, false)
1254+
1255+
INITIALIZE_PASS_BEGIN(RefPruneLegacyPass, "nrtRefPruneLegacyPass",
1256+
"Prune NRT refops", false, false)
11811257
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
11821258
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
11831259

1184-
INITIALIZE_PASS_END(RefPrunePass, "refprunepass", "Prune NRT refops", false,
1185-
false)
1260+
INITIALIZE_PASS_END(RefPruneLegacyPass, "RefPruneLegacyPass",
1261+
"Prune NRT refops", false, false)
1262+
11861263
extern "C" {
11871264

11881265
API_EXPORT(void)
1189-
LLVMPY_AddRefPrunePass(LLVMPassManagerRef PM, int subpasses,
1190-
size_t subgraph_limit) {
1191-
unwrap(PM)->add(new RefNormalizePass());
1266+
LLVMPY_AddLegacyRefPrunePass(LLVMPassManagerRef PM, int subpasses,
1267+
size_t subgraph_limit) {
1268+
unwrap(PM)->add(new RefNormalizeLegacyPass());
11921269
unwrap(PM)->add(
1193-
new RefPrunePass((RefPrunePass::Subpasses)subpasses, subgraph_limit));
1270+
new RefPruneLegacyPass((Subpasses)subpasses, subgraph_limit));
1271+
}
1272+
1273+
API_EXPORT(void)
1274+
LLVMPY_AddRefPrunePass_module(LLVMModulePassManagerRef MPM, int subpasses,
1275+
size_t subgraph_limit) {
1276+
llvm::unwrap(MPM)->addPass(
1277+
createModuleToFunctionPassAdaptor(RefNormalizePass()));
1278+
llvm::unwrap(MPM)->addPass(createModuleToFunctionPassAdaptor(
1279+
RefPrunePass((Subpasses)subpasses, subgraph_limit)));
1280+
}
1281+
1282+
API_EXPORT(void)
1283+
LLVMPY_AddRefPrunePass_function(LLVMFunctionPassManagerRef FPM, int subpasses,
1284+
size_t subgraph_limit) {
1285+
llvm::unwrap(FPM)->addPass(RefNormalizePass());
1286+
llvm::unwrap(FPM)->addPass(
1287+
RefPrunePass((Subpasses)subpasses, subgraph_limit));
11941288
}
11951289

11961290
/**
@@ -1207,24 +1301,22 @@ typedef struct PruneStats {
12071301
API_EXPORT(void)
12081302
LLVMPY_DumpRefPruneStats(PRUNESTATS *buf, bool do_print) {
12091303
/* PRUNESTATS is updated with the statistics about what has been pruned from
1210-
* the RefPrunePass static state vars. This isn't threadsafe but neither is
1304+
* the RefPrune static state vars. This isn't threadsafe but neither is
12111305
* the LLVM pass infrastructure so it's all done under a python thread lock.
12121306
*
12131307
* do_print if set will print the stats to stderr.
12141308
*/
12151309
if (do_print) {
1216-
errs() << "refprune stats "
1217-
<< "per-BB " << RefPrunePass::stats_per_bb << " "
1218-
<< "diamond " << RefPrunePass::stats_diamond << " "
1219-
<< "fanout " << RefPrunePass::stats_fanout << " "
1220-
<< "fanout+raise " << RefPrunePass::stats_fanout_raise << " "
1221-
<< "\n";
1310+
errs() << "refprune stats " << "per-BB " << RefPrune::stats_per_bb
1311+
<< " " << "diamond " << RefPrune::stats_diamond << " "
1312+
<< "fanout " << RefPrune::stats_fanout << " " << "fanout+raise "
1313+
<< RefPrune::stats_fanout_raise << " " << "\n";
12221314
};
12231315

1224-
buf->basicblock = RefPrunePass::stats_per_bb;
1225-
buf->diamond = RefPrunePass::stats_diamond;
1226-
buf->fanout = RefPrunePass::stats_fanout;
1227-
buf->fanout_raise = RefPrunePass::stats_fanout_raise;
1316+
buf->basicblock = RefPrune::stats_per_bb;
1317+
buf->diamond = RefPrune::stats_diamond;
1318+
buf->fanout = RefPrune::stats_fanout;
1319+
buf->fanout_raise = RefPrune::stats_fanout_raise;
12281320
}
12291321

12301322
} // extern "C"

llvmlite/binding/newpassmanagers.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from ctypes import c_bool, c_int
2+
from enum import IntFlag
23
from llvmlite.binding import ffi
34

45

@@ -18,6 +19,14 @@ def create_pipeline_tuning_options(speed_level=2, size_level=0):
1819
return PipelineTuningOptions(speed_level, size_level)
1920

2021

22+
class RefPruneSubpasses(IntFlag):
23+
PER_BB = 0b0001 # noqa: E221
24+
DIAMOND = 0b0010 # noqa: E221
25+
FANOUT = 0b0100 # noqa: E221
26+
FANOUT_RAISE = 0b1000
27+
ALL = PER_BB | DIAMOND | FANOUT | FANOUT_RAISE
28+
29+
2130
class ModulePassManager(ffi.ObjectRef):
2231

2332
def __init__(self, ptr=None):
@@ -52,6 +61,24 @@ def add_jump_threading_pass(self, threshold=-1):
5261
def _dispose(self):
5362
ffi.lib.LLVMPY_DisposeNewModulePassManger(self)
5463

64+
# Non-standard LLVM passes
65+
def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL,
66+
subgraph_limit=1000):
67+
"""Add Numba specific Reference count pruning pass.
68+
69+
Parameters
70+
----------
71+
subpasses_flags : RefPruneSubpasses
72+
A bitmask to control the subpasses to be enabled.
73+
subgraph_limit : int
74+
Limit the fanout pruners to working on a subgraph no bigger than
75+
this number of basic-blocks to avoid spending too much time in very
76+
large graphs. Default is 1000. Subject to change in future
77+
versions.
78+
"""
79+
iflags = RefPruneSubpasses(subpasses_flags)
80+
ffi.lib.LLVMPY_AddRefPrunePass_module(self, iflags, subgraph_limit)
81+
5582

5683
class FunctionPassManager(ffi.ObjectRef):
5784

@@ -84,6 +111,24 @@ def add_jump_threading_pass(self, threshold=-1):
84111
def _dispose(self):
85112
ffi.lib.LLVMPY_DisposeNewFunctionPassManger(self)
86113

114+
# Non-standard LLVM passes
115+
def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL,
116+
subgraph_limit=1000):
117+
"""Add Numba specific Reference count pruning pass.
118+
119+
Parameters
120+
----------
121+
subpasses_flags : RefPruneSubpasses
122+
A bitmask to control the subpasses to be enabled.
123+
subgraph_limit : int
124+
Limit the fanout pruners to working on a subgraph no bigger than
125+
this number of basic-blocks to avoid spending too much time in very
126+
large graphs. Default is 1000. Subject to change in future
127+
versions.
128+
"""
129+
iflags = RefPruneSubpasses(subpasses_flags)
130+
ffi.lib.LLVMPY_AddRefPrunePass_function(self, iflags, subgraph_limit)
131+
87132

88133
class PipelineTuningOptions(ffi.ObjectRef):
89134

0 commit comments

Comments
 (0)