Skip to content

Commit d1e1959

Browse files
committed
Visitor: Optimize core opcode and intrinsic ID lookup
Establish hash maps of core opcodes and intrinsic IDs that are being visited and use those for the lookups instead of iterating over all cases that have been added to the visitor. No intended interface change, although this does potentially affect the order in which callbacks are called, if multiple callbacks are installed that can match the same instruction. Callbacks installed for an explicit dialect op or intrinsic will always be called before one that has been installed for the generic CallInst core instruction type. If multiple handlers for the same instruction become an issue, we may want to allow some policies to be set in the future, including return values from the callbacks indicating whether an instruction should be processed further. This is still theoretical at the time of writing.
1 parent 7e30f59 commit d1e1959

File tree

2 files changed

+325
-148
lines changed

2 files changed

+325
-148
lines changed

include/llvm-dialects/Dialect/Visitor.h

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#pragma once
1818

19+
#include "llvm/ADT/DenseMap.h"
1920
#include "llvm/ADT/SmallVector.h"
2021
#include "llvm/Support/Casting.h"
2122

@@ -90,10 +91,11 @@ struct VisitorPayloadProjection {
9091
namespace detail {
9192

9293
class VisitorBase;
94+
class VisitorTemplate;
9395

9496
/// @brief Key describing the condition of a visitor case
9597
class VisitorKey {
96-
friend class VisitorBase;
98+
friend class VisitorTemplate;
9799

98100
public:
99101
template <typename OpT> static VisitorKey op() {
@@ -108,13 +110,6 @@ class VisitorKey {
108110
return key;
109111
}
110112

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-
118113
private:
119114
enum class Kind {
120115
OpDescription,
@@ -131,67 +126,123 @@ class VisitorKey {
131126
using VisitorCallback = void (void *, void *, llvm::Instruction *);
132127
using PayloadProjectionCallback = void *(void *);
133128

134-
/// Apply first the byte offset and then the projection function. If projection
135-
/// is null, stop the projection sequence.
136-
struct PayloadProjection {
137-
std::size_t offset = 0;
138-
PayloadProjectionCallback *projection = nullptr;
139-
};
140-
141-
struct VisitorCase {
142-
VisitorKey key;
129+
struct VisitorHandler {
143130
VisitorCallback *callback = nullptr;
144131
void *callbackData = nullptr;
145132

146133
// If non-negative, a byte offset to apply to the payload. If negative,
147-
// a shifted index into the projections vector.
134+
// a shifted index into the payload projections vector.
148135
ssize_t projection = 0;
136+
};
149137

150-
explicit VisitorCase(VisitorKey key) : key(key) {}
138+
/// Apply first the byte offset and then the projection function. If projection
139+
/// is null, stop the projection sequence.
140+
struct PayloadProjection {
141+
std::size_t offset = 0;
142+
PayloadProjectionCallback *projection = nullptr;
151143
};
152144

153145
template <typename PayloadT, typename NestedPayloadT>
154146
struct VisitorPayloadOffsetProjection {
155147
static constexpr bool useOffsetof = false;
156148
};
157149

150+
/// @brief Visitor description during build
151+
///
152+
/// These structures are built up incrementally when a visitor is setup. They
153+
/// are optimized when the final visitor is built.
154+
class VisitorTemplate {
155+
friend class VisitorBase;
156+
friend class VisitorBuilderBase;
157+
158+
public:
159+
void setStrategy(VisitorStrategy strategy);
160+
void add(VisitorKey key, void *extra, VisitorCallback *fn,
161+
ssize_t projection);
162+
163+
private:
164+
VisitorStrategy m_strategy = VisitorStrategy::Default;
165+
std::vector<PayloadProjection> m_projections;
166+
std::vector<VisitorHandler> m_handlers;
167+
llvm::DenseMap<unsigned, llvm::SmallVector<unsigned>> m_coreOpcodeMap;
168+
llvm::DenseMap<unsigned, llvm::SmallVector<unsigned>> m_intrinsicIdMap;
169+
std::vector<std::pair<const OpDescription *, llvm::SmallVector<unsigned>>>
170+
m_dialectCases;
171+
};
172+
173+
/// @brief Base class for VisitorBuilders
174+
///
175+
/// This class provides common functionality in a payload-type-erased manner.
158176
class VisitorBuilderBase {
159177
friend class VisitorBase;
178+
160179
public:
161-
VisitorBuilderBase() = default;
162-
explicit VisitorBuilderBase(VisitorBuilderBase *parent) : m_parent(parent) {}
163-
~VisitorBuilderBase();
180+
VisitorBuilderBase();
181+
VisitorBuilderBase(VisitorBuilderBase *parent,
182+
PayloadProjectionCallback *projection);
183+
VisitorBuilderBase(VisitorBuilderBase *parent, size_t offset);
184+
185+
VisitorBuilderBase(VisitorBuilderBase &&rhs)
186+
: m_ownedTemplate(std::move(rhs.m_ownedTemplate)),
187+
m_projection(rhs.m_projection) {
188+
assert(rhs.m_template == &rhs.m_ownedTemplate);
189+
m_template = &m_ownedTemplate;
190+
}
191+
VisitorBuilderBase &operator=(VisitorBuilderBase &&rhs) {
192+
assert(rhs.m_template == &rhs.m_ownedTemplate);
193+
if (this != &rhs) {
194+
m_ownedTemplate = std::move(rhs.m_ownedTemplate);
195+
m_template = &m_ownedTemplate;
196+
m_projection = rhs.m_projection;
197+
}
198+
return *this;
199+
}
164200

165201
void setStrategy(VisitorStrategy strategy);
166202

167203
void add(VisitorKey key, void *extra, VisitorCallback *fn);
168204

169-
public:
170-
PayloadProjectionCallback *m_projection = nullptr;
171-
size_t m_offsetProjection = 0;
205+
VisitorBase build();
172206

173207
private:
174-
VisitorBuilderBase *m_parent = nullptr;
175-
VisitorStrategy m_strategy = VisitorStrategy::Default;
176-
llvm::SmallVector<VisitorCase> m_cases;
177-
llvm::SmallVector<PayloadProjection> m_projections;
208+
VisitorBuilderBase(const VisitorBuilderBase &rhs) = delete;
209+
VisitorBuilderBase &operator=(const VisitorBuilderBase &rhs) = delete;
210+
211+
VisitorTemplate m_ownedTemplate;
212+
VisitorTemplate *m_template;
213+
ssize_t m_projection;
178214
};
179215

216+
/// @brief Base class for Visitors
217+
///
218+
/// Provides visitor functionality in a payload-type-erased manner.
180219
class VisitorBase {
181-
protected:
182-
VisitorBase(VisitorBuilderBase &&builder);
220+
public:
221+
VisitorBase(VisitorTemplate &&templ);
183222

184223
void visit(void *payload, llvm::Instruction &inst) const;
185224
void visit(void *payload, llvm::Function &fn) const;
186225
void visit(void *payload, llvm::Module &module) const;
187226

188227
private:
189-
void call(const VisitorCase &theCase, void *payload,
228+
class BuildHelper;
229+
using HandlerRange = std::pair<unsigned, unsigned>;
230+
231+
void call(HandlerRange handlers, void *payload,
232+
llvm::Instruction &inst) const;
233+
void call(const VisitorHandler &handler, void *payload,
190234
llvm::Instruction &inst) const;
191235

236+
template <typename FilterT>
237+
void visitByDeclarations(void *payload, llvm::Module &module,
238+
FilterT &&filter) const;
239+
192240
VisitorStrategy m_strategy;
193-
llvm::SmallVector<VisitorCase> m_cases;
194-
llvm::SmallVector<PayloadProjection> m_projections;
241+
std::vector<PayloadProjection> m_projections;
242+
std::vector<VisitorHandler> m_handlers;
243+
llvm::DenseMap<unsigned, HandlerRange> m_coreOpcodeMap;
244+
llvm::DenseMap<unsigned, HandlerRange> m_intrinsicIdMap;
245+
std::vector<std::pair<const OpDescription *, HandlerRange>> m_dialectCases;
195246
};
196247

197248
} // namespace detail
@@ -205,11 +256,9 @@ class VisitorBase {
205256
/// required, select the ReversePostOrder strategy at VisitorBuilder time.
206257
///
207258
/// Callbacks must not delete or remove their instruction argument.
208-
template <typename PayloadT>
209-
class Visitor : public detail::VisitorBase {
259+
template <typename PayloadT> class Visitor : private detail::VisitorBase {
210260
public:
211-
Visitor(detail::VisitorBuilderBase &&builder)
212-
: VisitorBase(std::move(builder)) {}
261+
Visitor(detail::VisitorBase &&base) : VisitorBase(std::move(base)) {}
213262

214263
void visit(PayloadT &payload, llvm::Instruction &inst) const {
215264
VisitorBase::visit(static_cast<void *>(&payload), inst);
@@ -260,7 +309,7 @@ class VisitorBuilder : private detail::VisitorBuilderBase {
260309
return *this;
261310
}
262311

263-
Visitor<PayloadT> build() { return std::move(*this); }
312+
Visitor<PayloadT> build() { return VisitorBuilderBase::build(); }
264313

265314
template <typename OpT> VisitorBuilder &add(void (*fn)(PayloadT &, OpT &)) {
266315
addCase<OpT>(detail::VisitorKey::op<OpT>(), fn);
@@ -275,29 +324,33 @@ class VisitorBuilder : private detail::VisitorBuilderBase {
275324

276325
template <typename NestedPayloadT>
277326
VisitorBuilder &nest(void (*registration)(VisitorBuilder<NestedPayloadT> &)) {
278-
VisitorBuilder<NestedPayloadT> nested{this};
279-
280327
if constexpr (detail::VisitorPayloadOffsetProjection<
281328
PayloadT, NestedPayloadT>::useOffsetof) {
282-
nested.m_offsetProjection =
329+
size_t offset =
283330
detail::VisitorPayloadOffsetProjection<PayloadT,
284331
NestedPayloadT>::offset;
332+
VisitorBuilder<NestedPayloadT> nested{this, offset};
333+
(*registration)(nested);
285334
} else {
286-
nested.m_projection = [](void *payload) -> void * {
335+
auto projection = [](void *payload) -> void * {
287336
return static_cast<void *>(
288337
&VisitorPayloadProjection<PayloadT, NestedPayloadT>::project(
289338
*static_cast<PayloadT *>(payload)));
290339
};
291-
}
292340

293-
(*registration)(nested);
341+
VisitorBuilder<NestedPayloadT> nested{this, projection};
342+
(*registration)(nested);
343+
}
294344

295345
return *this;
296346
}
297347

298348
private:
299-
explicit VisitorBuilder(VisitorBuilderBase *parent)
300-
: VisitorBuilderBase(parent) {}
349+
VisitorBuilder(VisitorBuilderBase *parent, size_t offset)
350+
: VisitorBuilderBase(parent, offset) {}
351+
VisitorBuilder(VisitorBuilderBase *parent,
352+
detail::PayloadProjectionCallback *projection)
353+
: VisitorBuilderBase(parent, projection) {}
301354

302355
template <typename OpT>
303356
void addCase(detail::VisitorKey key, void (*fn)(PayloadT &, OpT &)) {

0 commit comments

Comments
 (0)