Skip to content

Commit 7e30f59

Browse files
committed
Visitor: allow visiting core instructions and intrinsics
This is mostly built on an extension of OpDescription. - comment out references to dbg.addr, which is from fairly recent LLVM - use std::variant and ArrayRef in OpDescription
1 parent 97cbdfd commit 7e30f59

File tree

6 files changed

+451
-29
lines changed

6 files changed

+451
-29
lines changed

example/ExampleMain.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
#include "llvm/AsmParser/Parser.h"
3232
#include "llvm/IR/DerivedTypes.h"
33+
#include "llvm/IR/IntrinsicInst.h"
34+
#include "llvm/IR/Intrinsics.h"
3335
#include "llvm/IR/Module.h"
3436
#include "llvm/IRPrinter/IRPrintingPasses.h"
3537
#include "llvm/Support/CommandLine.h"
@@ -173,10 +175,24 @@ template <bool rpot> const Visitor<VisitorContainer> &getExampleVisitor() {
173175
b.add<xd::ReadOp>([](VisitorNest &self, xd::ReadOp &op) {
174176
*self.out << "visiting ReadOp: " << op << '\n';
175177
});
178+
b.add<UnaryInstruction>(
179+
[](VisitorNest &self, UnaryInstruction &inst) {
180+
*self.out << "visiting UnaryInstruction: " << inst << '\n';
181+
});
182+
b.add<BinaryOperator>([](VisitorNest &self, BinaryOperator &inst) {
183+
*self.out << "visiting BinaryOperator: " << inst << '\n';
184+
});
176185
b.nest<raw_ostream>([](VisitorBuilder<raw_ostream> &b) {
177186
b.add<xd::WriteOp>([](raw_ostream &out, xd::WriteOp &op) {
178187
out << "visiting WriteOp: " << op << '\n';
179188
});
189+
b.add<ReturnInst>([](raw_ostream &out, ReturnInst &ret) {
190+
out << "visiting ReturnInst: " << ret << '\n';
191+
});
192+
b.addIntrinsic(
193+
Intrinsic::umax, [](raw_ostream &out, IntrinsicInst &umax) {
194+
out << "visiting umax intrinsic: " << umax << '\n';
195+
});
180196
});
181197
b.nest<VisitorInnermost>([](VisitorBuilder<VisitorInnermost> &b) {
182198
b.add<xd::ITruncOp>([](VisitorInnermost &inner,

include/llvm-dialects/Dialect/OpDescription.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,59 @@
1616

1717
#pragma once
1818

19+
#include "llvm/ADT/ArrayRef.h"
1920
#include "llvm/ADT/StringRef.h"
2021

22+
#include <vector>
23+
2124
namespace llvm {
2225
class Function;
2326
class Instruction;
2427
} // namespace llvm
2528

2629
namespace llvm_dialects {
2730

28-
/// @brief Reflect an operation defined by a dialect
31+
/// @brief Reflect an operation.
2932
class OpDescription {
33+
public:
34+
enum class Kind {
35+
Core,
36+
Dialect,
37+
DialectWithOverloads,
38+
Intrinsic,
39+
};
40+
3041
public:
3142
OpDescription(bool hasOverloads, llvm::StringRef mnemonic)
32-
: m_hasOverloads(hasOverloads), m_mnemonic(mnemonic) {}
43+
: m_kind(hasOverloads ? Kind::DialectWithOverloads : Kind::Dialect),
44+
m_op(mnemonic) {}
45+
OpDescription(Kind kind, unsigned opcode) : m_kind(kind), m_op(opcode) {}
46+
OpDescription(Kind kind, llvm::MutableArrayRef<unsigned> opcodes);
3347

3448
template <typename OpT>
3549
static const OpDescription& get();
3650

51+
Kind getKind() const { return m_kind; }
52+
llvm::ArrayRef<unsigned> getOpcodes() const;
53+
3754
bool matchInstruction(llvm::Instruction &inst) const;
3855
bool matchDeclaration(llvm::Function &decl) const;
3956

57+
bool canMatchDeclaration() const {
58+
return m_kind == Kind::Dialect || m_kind == Kind::DialectWithOverloads ||
59+
m_kind == Kind::Intrinsic;
60+
}
61+
4062
private:
41-
bool m_hasOverloads;
42-
llvm::StringRef m_mnemonic;
63+
bool matchIntrinsic(unsigned intrinsicId) const;
64+
65+
Kind m_kind;
66+
67+
// Holds one of:
68+
// - core instruction opcode or intrinsic ID
69+
// - sorted array of opcodes or intrinsic IDs
70+
// - mnemonic
71+
std::variant<unsigned, llvm::ArrayRef<unsigned>, llvm::StringRef> m_op;
4372
};
4473

4574
} // namespace llvm_dialects

include/llvm-dialects/Dialect/Visitor.h

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
namespace llvm {
2525
class Function;
2626
class Instruction;
27+
class IntrinsicInst;
2728
class Module;
2829
} // namespace llvm
2930

@@ -90,6 +91,43 @@ namespace detail {
9091

9192
class VisitorBase;
9293

94+
/// @brief Key describing the condition of a visitor case
95+
class VisitorKey {
96+
friend class VisitorBase;
97+
98+
public:
99+
template <typename OpT> static VisitorKey op() {
100+
VisitorKey key{Kind::OpDescription};
101+
key.m_description = &OpDescription::get<OpT>();
102+
return key;
103+
}
104+
105+
static VisitorKey intrinsic(unsigned id) {
106+
VisitorKey key{Kind::Intrinsic};
107+
key.m_intrinsicId = id;
108+
return key;
109+
}
110+
111+
bool matchInstruction(llvm::Instruction &inst) const;
112+
bool matchDeclaration(llvm::Function &decl) const;
113+
114+
bool canMatchDeclaration() const {
115+
return m_kind == Kind::Intrinsic || m_description->canMatchDeclaration();
116+
}
117+
118+
private:
119+
enum class Kind {
120+
OpDescription,
121+
Intrinsic,
122+
};
123+
124+
VisitorKey(Kind kind) : m_kind(kind) {}
125+
126+
Kind m_kind;
127+
const OpDescription *m_description = nullptr;
128+
unsigned m_intrinsicId = 0;
129+
};
130+
93131
using VisitorCallback = void (void *, void *, llvm::Instruction *);
94132
using PayloadProjectionCallback = void *(void *);
95133

@@ -101,13 +139,15 @@ struct PayloadProjection {
101139
};
102140

103141
struct VisitorCase {
104-
const OpDescription *description = nullptr;
142+
VisitorKey key;
105143
VisitorCallback *callback = nullptr;
106144
void *callbackData = nullptr;
107145

108146
// If non-negative, a byte offset to apply to the payload. If negative,
109147
// a shifted index into the projections vector.
110148
ssize_t projection = 0;
149+
150+
explicit VisitorCase(VisitorKey key) : key(key) {}
111151
};
112152

113153
template <typename PayloadT, typename NestedPayloadT>
@@ -124,7 +164,7 @@ class VisitorBuilderBase {
124164

125165
void setStrategy(VisitorStrategy strategy);
126166

127-
void add(const OpDescription &desc, void *extra, VisitorCallback *fn);
167+
void add(VisitorKey key, void *extra, VisitorCallback *fn);
128168

129169
public:
130170
PayloadProjectionCallback *m_projection = nullptr;
@@ -223,13 +263,13 @@ class VisitorBuilder : private detail::VisitorBuilderBase {
223263
Visitor<PayloadT> build() { return std::move(*this); }
224264

225265
template <typename OpT> VisitorBuilder &add(void (*fn)(PayloadT &, OpT &)) {
226-
VisitorBuilderBase::add(
227-
OpDescription::get<OpT>(),
228-
(void *)fn,
229-
[](void *extra, void *payload, llvm::Instruction *op) {
230-
auto fn = (void (*)(PayloadT &, OpT &))extra;
231-
fn(*static_cast<PayloadT *>(payload), *llvm::cast<OpT>(op));
232-
});
266+
addCase<OpT>(detail::VisitorKey::op<OpT>(), fn);
267+
return *this;
268+
}
269+
270+
VisitorBuilder &addIntrinsic(unsigned id,
271+
void (*fn)(PayloadT &, llvm::IntrinsicInst &)) {
272+
addCase<llvm::IntrinsicInst>(detail::VisitorKey::intrinsic(id), fn);
233273
return *this;
234274
}
235275

@@ -258,6 +298,17 @@ class VisitorBuilder : private detail::VisitorBuilderBase {
258298
private:
259299
explicit VisitorBuilder(VisitorBuilderBase *parent)
260300
: VisitorBuilderBase(parent) {}
301+
302+
template <typename OpT>
303+
void addCase(detail::VisitorKey key, void (*fn)(PayloadT &, OpT &)) {
304+
VisitorBuilderBase::add(key, (void *)fn, &VisitorBuilder::forwarder<OpT>);
305+
}
306+
307+
template <typename OpT>
308+
static void forwarder(void *extra, void *payload, llvm::Instruction *op) {
309+
auto fn = (void (*)(PayloadT &, OpT &))extra;
310+
fn(*static_cast<PayloadT *>(payload), *llvm::cast<OpT>(op));
311+
}
261312
};
262313

263314
} // namespace llvm_dialects

0 commit comments

Comments
 (0)