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 {
9091namespace detail {
9192
9293class VisitorBase ;
94+ class VisitorTemplate ;
9395
9496// / @brief Key describing the condition of a visitor case
9597class VisitorKey {
96- friend class VisitorBase ;
98+ friend class VisitorTemplate ;
9799
98100public:
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-
118113private:
119114 enum class Kind {
120115 OpDescription,
@@ -131,67 +126,123 @@ class VisitorKey {
131126using VisitorCallback = void (void *, void *, llvm::Instruction *);
132127using 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
153145template <typename PayloadT, typename NestedPayloadT>
154146struct 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.
158176class VisitorBuilderBase {
159177 friend class VisitorBase ;
178+
160179public:
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
173207private:
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.
180219class 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
188227private:
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 {
210260public:
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
298348private:
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