Skip to content

Commit 97cbdfd

Browse files
committed
Visitor: Add VisitorStrategy::ReversePostOrder
This will be convenient for certain lowering passes that depend on substituting values in a more complex pattern than just via replaceAllUsesWith.
1 parent 55c4e43 commit 97cbdfd

File tree

4 files changed

+82
-7
lines changed

4 files changed

+82
-7
lines changed

example/ExampleMain.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ cl::list<std::string> g_inputs(cl::Positional, cl::ZeroOrMore,
5858
cl::opt<bool> g_typedPointers("typed-pointers", cl::init(false),
5959
cl::desc("Disable opaque pointers"));
6060

61+
cl::opt<bool> g_rpot("rpot", cl::init(false),
62+
cl::desc("Visit functions in reverse post-order"));
63+
6164
/// Test intrinsics that are generic over unnamed struct types.
6265
void useUnnamedStructTypes(Builder &b) {
6366
StructType *t1 = StructType::create({b.getInt32Ty()}, "");
@@ -156,8 +159,15 @@ struct llvm_dialects::VisitorPayloadProjection<VisitorNest, raw_ostream> {
156159
LLVM_DIALECTS_VISITOR_PAYLOAD_PROJECT_FIELD(VisitorContainer, nest)
157160
LLVM_DIALECTS_VISITOR_PAYLOAD_PROJECT_FIELD(VisitorNest, inner)
158161

159-
void exampleVisit(Module &module) {
160-
auto visitor =
162+
// Get a visitor with RPOT or default strategy.
163+
//
164+
// Using a template in this way is a bit convoluted, but the point here is to
165+
// demonstrate the pattern of constructing a visitor as a function-local
166+
// static variable whose initialization doesn't refer to any runtime values,
167+
// i.e. if C++ had a strong enough compile-time evaluation (constexpr), it
168+
// should be possible to evaluate the initialization entirely at compile-time.
169+
template <bool rpot> const Visitor<VisitorContainer> &getExampleVisitor() {
170+
static const auto visitor =
161171
VisitorBuilder<VisitorContainer>()
162172
.nest<VisitorNest>([](VisitorBuilder<VisitorNest> &b) {
163173
b.add<xd::ReadOp>([](VisitorNest &self, xd::ReadOp &op) {
@@ -173,7 +183,15 @@ void exampleVisit(Module &module) {
173183
xd::ITruncOp &op) { inner.counter++; });
174184
});
175185
})
186+
.setStrategy(rpot ? VisitorStrategy::ReversePostOrder
187+
: VisitorStrategy::Default)
176188
.build();
189+
return visitor;
190+
}
191+
192+
void exampleVisit(Module &module) {
193+
const auto &visitor =
194+
g_rpot ? getExampleVisitor<true>() : getExampleVisitor<false>();
177195

178196
VisitorContainer container;
179197
container.nest.out = &outs();

include/llvm-dialects/Dialect/Visitor.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ namespace llvm_dialects {
3232
template <typename PayloadT>
3333
class Visitor;
3434

35-
/// The strategy for implementation a visitor of dialect ops,
35+
/// The iteration strategy of Visitor.
3636
enum class VisitorStrategy {
37+
/// Pick a reasonable default.
38+
Default,
39+
3740
/// Iterate over all instructions to find the ones that match.
3841
ByInstruction,
3942

43+
/// Iterate over all instructions in reverse post-order.
44+
ReversePostOrder,
45+
4046
/// Iterate over the function declarations in a module, filter out those for
4147
/// relevant dialect ops, and then iterate over their users.
4248
///
@@ -116,7 +122,7 @@ class VisitorBuilderBase {
116122
explicit VisitorBuilderBase(VisitorBuilderBase *parent) : m_parent(parent) {}
117123
~VisitorBuilderBase();
118124

119-
void setStrategy(VisitorStrategy strategy) { m_strategy = strategy; }
125+
void setStrategy(VisitorStrategy strategy);
120126

121127
void add(const OpDescription &desc, void *extra, VisitorCallback *fn);
122128

@@ -126,7 +132,7 @@ class VisitorBuilderBase {
126132

127133
private:
128134
VisitorBuilderBase *m_parent = nullptr;
129-
VisitorStrategy m_strategy = VisitorStrategy::ByFunctionDeclaration;
135+
VisitorStrategy m_strategy = VisitorStrategy::Default;
130136
llvm::SmallVector<VisitorCase> m_cases;
131137
llvm::SmallVector<PayloadProjection> m_projections;
132138
};
@@ -155,7 +161,8 @@ class VisitorBase {
155161
/// See @ref VisitorBuilder for how to instantiate this class.
156162
///
157163
/// Instructions are not necessarily visited in the order in which they appear
158-
/// in the containing function or even basic block.
164+
/// in the containing function or even basic block. If a fixed order is
165+
/// required, select the ReversePostOrder strategy at VisitorBuilder time.
159166
///
160167
/// Callbacks must not delete or remove their instruction argument.
161168
template <typename PayloadT>

lib/Dialect/Visitor.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm-dialects/Dialect/Visitor.h"
1818

19+
#include "llvm/ADT/PostOrderIterator.h"
1920
#include "llvm/IR/Function.h"
2021
#include "llvm/IR/Instructions.h"
2122
#include "llvm/IR/Module.h"
@@ -60,9 +61,20 @@ VisitorBuilderBase::~VisitorBuilderBase() {
6061

6162
// Copy all cases to the root.
6263
ancestor->m_cases.append(m_cases.begin(), m_cases.end());
64+
65+
ancestor->setStrategy(m_strategy);
6366
}
6467
}
6568

69+
void VisitorBuilderBase::setStrategy(VisitorStrategy strategy) {
70+
if (strategy == VisitorStrategy::Default)
71+
return;
72+
73+
assert(m_strategy == VisitorStrategy::Default || m_strategy == strategy);
74+
75+
m_strategy = strategy;
76+
}
77+
6678
void VisitorBuilderBase::add(const OpDescription &desc, void *extra, VisitorCallback *fn) {
6779
VisitorCase theCase;
6880
theCase.description = &desc;
@@ -76,6 +88,9 @@ VisitorBase::VisitorBase(VisitorBuilderBase &&builder)
7688
: m_strategy(builder.m_strategy), m_cases(std::move(builder.m_cases)),
7789
m_projections(std::move(builder.m_projections)) {
7890
assert(!builder.m_parent);
91+
92+
if (m_strategy == VisitorStrategy::Default)
93+
m_strategy = VisitorStrategy::ByFunctionDeclaration;
7994
}
8095

8196
void VisitorBase::call(const VisitorCase &theCase, void *payload,
@@ -109,6 +124,15 @@ void VisitorBase::visit(void *payload, Function &fn) const {
109124
return;
110125
}
111126

127+
if (m_strategy == VisitorStrategy::ReversePostOrder) {
128+
ReversePostOrderTraversal<Function *> rpot(&fn);
129+
for (BasicBlock *bb : rpot) {
130+
for (Instruction &inst : *bb)
131+
visit(payload, inst);
132+
}
133+
return;
134+
}
135+
112136
for (Function &decl : fn.getParent()->functions()) {
113137
if (!decl.isDeclaration())
114138
continue;
@@ -133,7 +157,7 @@ void VisitorBase::visit(void *payload, Function &fn) const {
133157
}
134158

135159
void VisitorBase::visit(void *payload, Module &module) const {
136-
if (m_strategy == VisitorStrategy::ByInstruction) {
160+
if (m_strategy != VisitorStrategy::ByFunctionDeclaration) {
137161
for (Function &fn : module.functions()) {
138162
if (!fn.isDeclaration())
139163
visit(payload, fn);

test/example/visitor-rpot.ll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
; RUN: llvm-dialects-example -visit %s | FileCheck --check-prefixes=DEFAULT %s
2+
; RUN: llvm-dialects-example -visit -rpot %s | FileCheck --check-prefixes=RPOT %s
3+
4+
; DEFAULT: visiting WriteOp: call void (...) @xd.write(i32 0)
5+
; DEFAULT: visiting WriteOp: call void (...) @xd.write(i32 2)
6+
; DEFAULT: visiting WriteOp: call void (...) @xd.write(i32 1)
7+
8+
; RPOT: visiting WriteOp: call void (...) @xd.write(i32 0)
9+
; RPOT: visiting WriteOp: call void (...) @xd.write(i32 1)
10+
; RPOT: visiting WriteOp: call void (...) @xd.write(i32 2)
11+
12+
define void @test1(ptr %p) {
13+
entry:
14+
call void (...) @xd.write(i32 0)
15+
br label %a
16+
17+
b:
18+
call void (...) @xd.write(i32 2)
19+
ret void
20+
21+
a:
22+
call void (...) @xd.write(i32 1)
23+
br label %b
24+
}
25+
26+
declare void @xd.write(...)

0 commit comments

Comments
 (0)