aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/include/llvm/IR/InstVisitor.h
blob: cff803113fdb428b1cbfbef3b0a3121eecc4076e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

//===- InstVisitor.h - Instruction visitor templates ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//


#ifndef LLVM_IR_INSTVISITOR_H
#define LLVM_IR_INSTVISITOR_H

#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"

namespace llvm {

// We operate on opaque instruction classes, so forward declare all instruction
// types now...
//
#define HANDLE_INST(NUM, OPCODE, CLASS)   class CLASS;
#include "llvm/IR/Instruction.def"

#define DELEGATE(CLASS_TO_VISIT) \
  return static_cast<SubClass*>(this)-> \
               visit##CLASS_TO_VISIT(static_cast<CLASS_TO_VISIT&>(I))


/// Base class for instruction visitors
///
/// Instruction visitors are used when you want to perform different actions
/// for different kinds of instructions without having to use lots of casts
/// and a big switch statement (in your code, that is).
///
/// To define your own visitor, inherit from this class, specifying your
/// new type for the 'SubClass' template parameter, and "override" visitXXX
/// functions in your class. I say "override" because this class is defined
/// in terms of statically resolved overloading, not virtual functions.
///
/// For example, here is a visitor that counts the number of malloc
/// instructions processed:
///
///  /// Declare the class.  Note that we derive from InstVisitor instantiated
///  /// with _our new subclasses_ type.
///  ///
///  struct CountAllocaVisitor : public InstVisitor<CountAllocaVisitor> {
///    unsigned Count;
///    CountAllocaVisitor() : Count(0) {}
///
///    void visitAllocaInst(AllocaInst &AI) { ++Count; }
///  };
///
///  And this class would be used like this:
///    CountAllocaVisitor CAV;
///    CAV.visit(function);
///    NumAllocas = CAV.Count;
///
/// The defined has 'visit' methods for Instruction, and also for BasicBlock,
/// Function, and Module, which recursively process all contained instructions.
///
/// Note that if you don't implement visitXXX for some instruction type,
/// the visitXXX method for instruction superclass will be invoked. So
/// if instructions are added in the future, they will be automatically
/// supported, if you handle one of their superclasses.
///
/// The optional second template argument specifies the type that instruction
/// visitation functions should return. If you specify this, you *MUST* provide
/// an implementation of visitInstruction though!.
///
/// Note that this class is specifically designed as a template to avoid
/// virtual function call overhead.  Defining and using an InstVisitor is just
/// as efficient as having your own switch statement over the instruction
/// opcode.
template<typename SubClass, typename RetTy=void>
class InstVisitor {
  //===--------------------------------------------------------------------===//
  // Interface code - This is the public interface of the InstVisitor that you
  // use to visit instructions...
  //

public:
  // Generic visit method - Allow visitation to all instructions in a range
  template<class Iterator>
  void visit(Iterator Start, Iterator End) {
    while (Start != End)
      static_cast<SubClass*>(this)->visit(*Start++);
  }

  // Define visitors for functions and basic blocks...
  //
  void visit(Module &M) {
    static_cast<SubClass*>(this)->visitModule(M);
    visit(M.begin(), M.end());
  }
  void visit(Function &F) {
    static_cast<SubClass*>(this)->visitFunction(F);
    visit(F.begin(), F.end());
  }
  void visit(BasicBlock &BB) {
    static_cast<SubClass*>(this)->visitBasicBlock(BB);
    visit(BB.begin(), BB.end());
  }

  // Forwarding functions so that the user can visit with pointers AND refs.
  void visit(Module       *M)  { visit(*M); }
  void visit(Function     *F)  { visit(*F); }
  void visit(BasicBlock   *BB) { visit(*BB); }
  RetTy visit(Instruction *I)  { return visit(*I); }

  // visit - Finally, code to visit an instruction...
  //
  RetTy visit(Instruction &I) {
    static_assert(std::is_base_of<InstVisitor, SubClass>::value,
                  "Must pass the derived type to this template!");

    switch (I.getOpcode()) {
    default: llvm_unreachable("Unknown instruction type encountered!");
      // Build the switch statement using the Instruction.def file...
#define HANDLE_INST(NUM, OPCODE, CLASS) \
    case Instruction::OPCODE: return \
           static_cast<SubClass*>(this)-> \
                      visit##OPCODE(static_cast<CLASS&>(I));
#include "llvm/IR/Instruction.def"
    }
  }

  //===--------------------------------------------------------------------===//
  // Visitation functions... these functions provide default fallbacks in case
  // the user does not specify what to do for a particular instruction type.
  // The default behavior is to generalize the instruction type to its subtype
  // and try visiting the subtype.  All of this should be inlined perfectly,
  // because there are no virtual functions to get in the way.
  //

  // When visiting a module, function or basic block directly, these methods get
  // called to indicate when transitioning into a new unit.
  //
  void visitModule    (Module &M) {}
  void visitFunction  (Function &F) {}
  void visitBasicBlock(BasicBlock &BB) {}

  // Define instruction specific visitor functions that can be overridden to
  // handle SPECIFIC instructions.  These functions automatically define
  // visitMul to proxy to visitBinaryOperator for instance in case the user does
  // not need this generality.
  //
  // These functions can also implement fan-out, when a single opcode and
  // instruction have multiple more specific Instruction subclasses. The Call
  // instruction currently supports this. We implement that by redirecting that
  // instruction to a special delegation helper.
#define HANDLE_INST(NUM, OPCODE, CLASS) \
    RetTy visit##OPCODE(CLASS &I) { \
      if (NUM == Instruction::Call) \
        return delegateCallInst(I); \
      else \
        DELEGATE(CLASS); \
    }
#include "llvm/IR/Instruction.def"

  // Specific Instruction type classes... note that all of the casts are
  // necessary because we use the instruction classes as opaque types...
  //
  RetTy visitICmpInst(ICmpInst &I)                { DELEGATE(CmpInst);}
  RetTy visitFCmpInst(FCmpInst &I)                { DELEGATE(CmpInst);}
  RetTy visitAllocaInst(AllocaInst &I)            { DELEGATE(UnaryInstruction);}
  RetTy visitLoadInst(LoadInst     &I)            { DELEGATE(UnaryInstruction);}
  RetTy visitStoreInst(StoreInst   &I)            { DELEGATE(Instruction);}
  RetTy visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { DELEGATE(Instruction);}
  RetTy visitAtomicRMWInst(AtomicRMWInst &I)      { DELEGATE(Instruction);}
  RetTy visitFenceInst(FenceInst   &I)            { DELEGATE(Instruction);}
  RetTy visitGetElementPtrInst(GetElementPtrInst &I){ DELEGATE(Instruction);}
  RetTy visitPHINode(PHINode       &I)            { DELEGATE(Instruction);}
  RetTy visitTruncInst(TruncInst &I)              { DELEGATE(CastInst);}
  RetTy visitZExtInst(ZExtInst &I)                { DELEGATE(CastInst);}
  RetTy visitSExtInst(SExtInst &I)                { DELEGATE(CastInst);}
  RetTy visitFPTruncInst(FPTruncInst &I)          { DELEGATE(CastInst);}
  RetTy visitFPExtInst(FPExtInst &I)              { DELEGATE(CastInst);}
  RetTy visitFPToUIInst(FPToUIInst &I)            { DELEGATE(CastInst);}
  RetTy visitFPToSIInst(FPToSIInst &I)            { DELEGATE(CastInst);}
  RetTy visitUIToFPInst(UIToFPInst &I)            { DELEGATE(CastInst);}
  RetTy visitSIToFPInst(SIToFPInst &I)            { DELEGATE(CastInst);}
  RetTy visitPtrToIntInst(PtrToIntInst &I)        { DELEGATE(CastInst);}
  RetTy visitIntToPtrInst(IntToPtrInst &I)        { DELEGATE(CastInst);}
  RetTy visitBitCastInst(BitCastInst &I)          { DELEGATE(CastInst);}
  RetTy visitAddrSpaceCastInst(AddrSpaceCastInst &I) { DELEGATE(CastInst);}
  RetTy visitSelectInst(SelectInst &I)            { DELEGATE(Instruction);}
  RetTy visitVAArgInst(VAArgInst   &I)            { DELEGATE(UnaryInstruction);}
  RetTy visitExtractElementInst(ExtractElementInst &I) { DELEGATE(Instruction);}
  RetTy visitInsertElementInst(InsertElementInst &I) { DELEGATE(Instruction);}
  RetTy visitShuffleVectorInst(ShuffleVectorInst &I) { DELEGATE(Instruction);}
  RetTy visitExtractValueInst(ExtractValueInst &I){ DELEGATE(UnaryInstruction);}
  RetTy visitInsertValueInst(InsertValueInst &I)  { DELEGATE(Instruction); }
  RetTy visitLandingPadInst(LandingPadInst &I)    { DELEGATE(Instruction); }
  RetTy visitFuncletPadInst(FuncletPadInst &I) { DELEGATE(Instruction); }
  RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); }
  RetTy visitCatchPadInst(CatchPadInst &I)     { DELEGATE(FuncletPadInst); }
  RetTy visitFreezeInst(FreezeInst &I)         { DELEGATE(Instruction); }

  // Handle the special intrinsic instruction classes.
  RetTy visitDbgDeclareInst(DbgDeclareInst &I)    { DELEGATE(DbgVariableIntrinsic);}
  RetTy visitDbgValueInst(DbgValueInst &I)        { DELEGATE(DbgVariableIntrinsic);}
  RetTy visitDbgVariableIntrinsic(DbgVariableIntrinsic &I)
                                                  { DELEGATE(DbgInfoIntrinsic);}
  RetTy visitDbgLabelInst(DbgLabelInst &I)        { DELEGATE(DbgInfoIntrinsic);}
  RetTy visitDbgInfoIntrinsic(DbgInfoIntrinsic &I){ DELEGATE(IntrinsicInst); }
  RetTy visitMemSetInst(MemSetInst &I)            { DELEGATE(MemIntrinsic); }
  RetTy visitMemSetInlineInst(MemSetInlineInst &I){ DELEGATE(MemSetInst); }
  RetTy visitMemCpyInst(MemCpyInst &I)            { DELEGATE(MemTransferInst); }
  RetTy visitMemCpyInlineInst(MemCpyInlineInst &I){ DELEGATE(MemCpyInst); }
  RetTy visitMemMoveInst(MemMoveInst &I)          { DELEGATE(MemTransferInst); }
  RetTy visitMemTransferInst(MemTransferInst &I)  { DELEGATE(MemIntrinsic); }
  RetTy visitMemIntrinsic(MemIntrinsic &I)        { DELEGATE(IntrinsicInst); }
  RetTy visitVAStartInst(VAStartInst &I)          { DELEGATE(IntrinsicInst); }
  RetTy visitVAEndInst(VAEndInst &I)              { DELEGATE(IntrinsicInst); }
  RetTy visitVACopyInst(VACopyInst &I)            { DELEGATE(IntrinsicInst); }
  RetTy visitIntrinsicInst(IntrinsicInst &I)      { DELEGATE(CallInst); }
  RetTy visitCallInst(CallInst &I)                { DELEGATE(CallBase); }
  RetTy visitInvokeInst(InvokeInst &I)            { DELEGATE(CallBase); }
  RetTy visitCallBrInst(CallBrInst &I)            { DELEGATE(CallBase); }

  // While terminators don't have a distinct type modeling them, we support
  // intercepting them with dedicated a visitor callback.
  RetTy visitReturnInst(ReturnInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitBranchInst(BranchInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitSwitchInst(SwitchInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitIndirectBrInst(IndirectBrInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitResumeInst(ResumeInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitUnreachableInst(UnreachableInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitCleanupReturnInst(CleanupReturnInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitCatchReturnInst(CatchReturnInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitCatchSwitchInst(CatchSwitchInst &I) {
    return static_cast<SubClass *>(this)->visitTerminator(I);
  }
  RetTy visitTerminator(Instruction &I)    { DELEGATE(Instruction);}

  // Next level propagators: If the user does not overload a specific
  // instruction type, they can overload one of these to get the whole class
  // of instructions...
  //
  RetTy visitCastInst(CastInst &I)                { DELEGATE(UnaryInstruction);}
  RetTy visitUnaryOperator(UnaryOperator &I)      { DELEGATE(UnaryInstruction);}
  RetTy visitBinaryOperator(BinaryOperator &I)    { DELEGATE(Instruction);}
  RetTy visitCmpInst(CmpInst &I)                  { DELEGATE(Instruction);}
  RetTy visitUnaryInstruction(UnaryInstruction &I){ DELEGATE(Instruction);}

  // The next level delegation for `CallBase` is slightly more complex in order
  // to support visiting cases where the call is also a terminator.
  RetTy visitCallBase(CallBase &I) {
    if (isa<InvokeInst>(I) || isa<CallBrInst>(I))
      return static_cast<SubClass *>(this)->visitTerminator(I);

    DELEGATE(Instruction);
  }

  // If the user wants a 'default' case, they can choose to override this
  // function.  If this function is not overloaded in the user's subclass, then
  // this instruction just gets ignored.
  //
  // Note that you MUST override this function if your return type is not void.
  //
  void visitInstruction(Instruction &I) {}  // Ignore unhandled instructions

private:
  // Special helper function to delegate to CallInst subclass visitors.
  RetTy delegateCallInst(CallInst &I) {
    if (const Function *F = I.getCalledFunction()) {
      switch (F->getIntrinsicID()) {
      default:                     DELEGATE(IntrinsicInst);
      case Intrinsic::dbg_declare: DELEGATE(DbgDeclareInst);
      case Intrinsic::dbg_value:   DELEGATE(DbgValueInst);
      case Intrinsic::dbg_label:   DELEGATE(DbgLabelInst);
      case Intrinsic::memcpy:      DELEGATE(MemCpyInst);
      case Intrinsic::memcpy_inline:
        DELEGATE(MemCpyInlineInst);
      case Intrinsic::memmove:     DELEGATE(MemMoveInst);
      case Intrinsic::memset:      DELEGATE(MemSetInst);
      case Intrinsic::memset_inline:
        DELEGATE(MemSetInlineInst);
      case Intrinsic::vastart:     DELEGATE(VAStartInst);
      case Intrinsic::vaend:       DELEGATE(VAEndInst);
      case Intrinsic::vacopy:      DELEGATE(VACopyInst);
      case Intrinsic::not_intrinsic: break;
      }
    }
    DELEGATE(CallInst);
  }

  // An overload that will never actually be called, it is used only from dead
  // code in the dispatching from opcodes to instruction subclasses.
  RetTy delegateCallInst(Instruction &I) {
    llvm_unreachable("delegateCallInst called for non-CallInst");
  }
};

#undef DELEGATE

} // End llvm namespace

#endif

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif