LLVM 20.0.0git
Tracker.h
Go to the documentation of this file.
1//===- Tracker.h ------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is the component of SandboxIR that tracks all changes made to its
10// state, such that we can revert the state when needed.
11//
12// Tracking changes
13// ----------------
14// The user needs to call `Tracker::save()` to enable tracking changes
15// made to SandboxIR. From that point on, any change made to SandboxIR, will
16// automatically create a change tracking object and register it with the
17// tracker. IR-change objects are subclasses of `IRChangeBase` and get
18// registered with the `Tracker::track()` function. The change objects
19// are saved in the order they are registered with the tracker and are stored in
20// the `Tracker::Changes` vector. All of this is done transparently to
21// the user.
22//
23// Reverting changes
24// -----------------
25// Calling `Tracker::revert()` will restore the state saved when
26// `Tracker::save()` was called. Internally this goes through the
27// change objects in `Tracker::Changes` in reverse order, calling their
28// `IRChangeBase::revert()` function one by one.
29//
30// Accepting changes
31// -----------------
32// The user needs to either revert or accept changes before the tracker object
33// is destroyed. This is enforced in the tracker's destructor.
34// This is the job of `Tracker::accept()`. Internally this will go
35// through the change objects in `Tracker::Changes` in order, calling
36// `IRChangeBase::accept()`.
37//
38//===----------------------------------------------------------------------===//
39
40#ifndef LLVM_SANDBOXIR_TRACKER_H
41#define LLVM_SANDBOXIR_TRACKER_H
42
45#include "llvm/IR/IRBuilder.h"
46#include "llvm/IR/Instruction.h"
47#include "llvm/IR/Module.h"
48#include "llvm/SandboxIR/Use.h"
49#include "llvm/Support/Debug.h"
50#include <memory>
51#include <regex>
52
53namespace llvm::sandboxir {
54
55class BasicBlock;
56class CallBrInst;
57class LoadInst;
58class StoreInst;
59class Instruction;
60class Tracker;
61class AllocaInst;
62class CatchSwitchInst;
63class SwitchInst;
64class ConstantInt;
65
66/// The base class for IR Change classes.
68protected:
69 friend class Tracker; // For Parent.
70
71public:
72 /// This runs when changes get reverted.
73 virtual void revert(Tracker &Tracker) = 0;
74 /// This runs when changes get accepted.
75 virtual void accept() = 0;
76 virtual ~IRChangeBase() = default;
77#ifndef NDEBUG
78 virtual void dump(raw_ostream &OS) const = 0;
79 LLVM_DUMP_METHOD virtual void dump() const = 0;
81 C.dump(OS);
82 return OS;
83 }
84#endif
85};
86
87/// Tracks the change of the source Value of a sandboxir::Use.
88class UseSet : public IRChangeBase {
89 Use U;
90 Value *OrigV = nullptr;
91
92public:
93 UseSet(const Use &U) : U(U), OrigV(U.get()) {}
94 void revert(Tracker &Tracker) final { U.set(OrigV); }
95 void accept() final {}
96#ifndef NDEBUG
97 void dump(raw_ostream &OS) const final { OS << "UseSet"; }
98 LLVM_DUMP_METHOD void dump() const final;
99#endif
100};
101
103 PHINode *PHI;
104 unsigned RemovedIdx;
105 Value *RemovedV;
106 BasicBlock *RemovedBB;
107
108public:
109 PHIRemoveIncoming(PHINode *PHI, unsigned RemovedIdx);
110 void revert(Tracker &Tracker) final;
111 void accept() final {}
112#ifndef NDEBUG
113 void dump(raw_ostream &OS) const final { OS << "PHISetIncoming"; }
114 LLVM_DUMP_METHOD void dump() const final;
115#endif
116};
117
119 PHINode *PHI;
120 unsigned Idx;
121
122public:
124 void revert(Tracker &Tracker) final;
125 void accept() final {}
126#ifndef NDEBUG
127 void dump(raw_ostream &OS) const final { OS << "PHISetIncoming"; }
128 LLVM_DUMP_METHOD void dump() const final;
129#endif
130};
131
132/// Tracks swapping a Use with another Use.
133class UseSwap : public IRChangeBase {
134 Use ThisUse;
135 Use OtherUse;
136
137public:
138 UseSwap(const Use &ThisUse, const Use &OtherUse)
139 : ThisUse(ThisUse), OtherUse(OtherUse) {
140 assert(ThisUse.getUser() == OtherUse.getUser() && "Expected same user!");
141 }
142 void revert(Tracker &Tracker) final { ThisUse.swap(OtherUse); }
143 void accept() final {}
144#ifndef NDEBUG
145 void dump(raw_ostream &OS) const final { OS << "UseSwap"; }
146 LLVM_DUMP_METHOD void dump() const final;
147#endif
148};
149
151 /// Contains all the data we need to restore an "erased" (i.e., detached)
152 /// instruction: the instruction itself and its operands in order.
153 struct InstrAndOperands {
154 /// The operands that got dropped.
156 /// The instruction that got "erased".
157 llvm::Instruction *LLVMI;
158 };
159 /// The instruction data is in reverse program order, which helps create the
160 /// original program order during revert().
162 /// This is either the next Instruction in the stream, or the parent
163 /// BasicBlock if at the end of the BB.
165 /// We take ownership of the "erased" instruction.
166 std::unique_ptr<sandboxir::Value> ErasedIPtr;
167
168public:
169 EraseFromParent(std::unique_ptr<sandboxir::Value> &&IPtr);
170 void revert(Tracker &Tracker) final;
171 void accept() final;
172#ifndef NDEBUG
173 void dump(raw_ostream &OS) const final { OS << "EraseFromParent"; }
174 LLVM_DUMP_METHOD void dump() const final;
176 C.dump(OS);
177 return OS;
178 }
179#endif
180};
181
183 /// The instruction that is about to get removed.
184 Instruction *RemovedI = nullptr;
185 /// This is either the next instr, or the parent BB if at the end of the BB.
187
188public:
189 RemoveFromParent(Instruction *RemovedI);
190 void revert(Tracker &Tracker) final;
191 void accept() final {};
192 Instruction *getInstruction() const { return RemovedI; }
193#ifndef NDEBUG
194 void dump(raw_ostream &OS) const final { OS << "RemoveFromParent"; }
195 LLVM_DUMP_METHOD void dump() const final;
196#endif // NDEBUG
197};
198
199/// This class can be used for tracking most instruction setters.
200/// The two template arguments are:
201/// - GetterFn: The getter member function pointer (e.g., `&Foo::get`)
202/// - SetterFn: The setter member function pointer (e.g., `&Foo::set`)
203/// Upon construction, it saves a copy of the original value by calling the
204/// getter function. Revert sets the value back to the one saved, using the
205/// setter function provided.
206///
207/// Example:
208/// Tracker.track(std::make_unique<
209/// GenericSetter<&FooInst::get, &FooInst::set>>(I, Tracker));
210///
211template <auto GetterFn, auto SetterFn>
212class GenericSetter final : public IRChangeBase {
213 /// Traits for getting the class type from GetterFn type.
214 template <typename> struct GetClassTypeFromGetter;
215 template <typename RetT, typename ClassT>
216 struct GetClassTypeFromGetter<RetT (ClassT::*)() const> {
217 using ClassType = ClassT;
218 };
219 using InstrT = typename GetClassTypeFromGetter<decltype(GetterFn)>::ClassType;
220 using SavedValT = std::invoke_result_t<decltype(GetterFn), InstrT>;
221 InstrT *I;
222 SavedValT OrigVal;
223
224public:
225 GenericSetter(InstrT *I) : I(I), OrigVal((I->*GetterFn)()) {}
226 void revert(Tracker &Tracker) final { (I->*SetterFn)(OrigVal); }
227 void accept() final {}
228#ifndef NDEBUG
229 void dump(raw_ostream &OS) const final { OS << "GenericSetter"; }
231 dump(dbgs());
232 dbgs() << "\n";
233 }
234#endif
235};
236
237/// Similar to GenericSetter but the setters/getters have an index as their
238/// first argument. This is commont in cases like: getOperand(unsigned Idx)
239template <auto GetterFn, auto SetterFn>
240class GenericSetterWithIdx final : public IRChangeBase {
241 /// Helper for getting the class type from the getter
242 template <typename ClassT, typename RetT>
243 static ClassT getClassTypeFromGetter(RetT (ClassT::*Fn)(unsigned) const);
244 template <typename ClassT, typename RetT>
245 static ClassT getClassTypeFromGetter(RetT (ClassT::*Fn)(unsigned));
246
247 using InstrT = decltype(getClassTypeFromGetter(GetterFn));
248 using SavedValT = std::invoke_result_t<decltype(GetterFn), InstrT, unsigned>;
249 InstrT *I;
250 SavedValT OrigVal;
251 unsigned Idx;
252
253public:
254 GenericSetterWithIdx(InstrT *I, unsigned Idx)
255 : I(I), OrigVal((I->*GetterFn)(Idx)), Idx(Idx) {}
256 void revert(Tracker &Tracker) final { (I->*SetterFn)(Idx, OrigVal); }
257 void accept() final {}
258#ifndef NDEBUG
259 void dump(raw_ostream &OS) const final { OS << "GenericSetterWithIdx"; }
261 dump(dbgs());
262 dbgs() << "\n";
263 }
264#endif
265};
266
268 CatchSwitchInst *CSI;
269 unsigned HandlerIdx;
270
271public:
273 void revert(Tracker &Tracker) final;
274 void accept() final {}
275#ifndef NDEBUG
276 void dump(raw_ostream &OS) const final { OS << "CatchSwitchAddHandler"; }
278 dump(dbgs());
279 dbgs() << "\n";
280 }
281#endif // NDEBUG
282};
283
285 SwitchInst *Switch;
286 ConstantInt *Val;
287
288public:
290 : Switch(Switch), Val(Val) {}
291 void revert(Tracker &Tracker) final;
292 void accept() final {}
293#ifndef NDEBUG
294 void dump(raw_ostream &OS) const final { OS << "SwitchAddCase"; }
295 LLVM_DUMP_METHOD void dump() const final;
296#endif // NDEBUG
297};
298
300 SwitchInst *Switch;
301 ConstantInt *Val;
302 BasicBlock *Dest;
303
304public:
306 : Switch(Switch), Val(Val), Dest(Dest) {}
307 void revert(Tracker &Tracker) final;
308 void accept() final {}
309#ifndef NDEBUG
310 void dump(raw_ostream &OS) const final { OS << "SwitchRemoveCase"; }
311 LLVM_DUMP_METHOD void dump() const final;
312#endif // NDEBUG
313};
314
315class MoveInstr : public IRChangeBase {
316 /// The instruction that moved.
317 Instruction *MovedI;
318 /// This is either the next instruction in the block, or the parent BB if at
319 /// the end of the BB.
321
322public:
324 void revert(Tracker &Tracker) final;
325 void accept() final {}
326#ifndef NDEBUG
327 void dump(raw_ostream &OS) const final { OS << "MoveInstr"; }
328 LLVM_DUMP_METHOD void dump() const final;
329#endif // NDEBUG
330};
331
332class InsertIntoBB final : public IRChangeBase {
333 Instruction *InsertedI = nullptr;
334
335public:
336 InsertIntoBB(Instruction *InsertedI);
337 void revert(Tracker &Tracker) final;
338 void accept() final {}
339#ifndef NDEBUG
340 void dump(raw_ostream &OS) const final { OS << "InsertIntoBB"; }
341 LLVM_DUMP_METHOD void dump() const final;
342#endif // NDEBUG
343};
344
345class CreateAndInsertInst final : public IRChangeBase {
346 Instruction *NewI = nullptr;
347
348public:
349 CreateAndInsertInst(Instruction *NewI) : NewI(NewI) {}
350 void revert(Tracker &Tracker) final;
351 void accept() final {}
352#ifndef NDEBUG
353 void dump(raw_ostream &OS) const final { OS << "CreateAndInsertInst"; }
354 LLVM_DUMP_METHOD void dump() const final;
355#endif
356};
357
358/// The tracker collects all the change objects and implements the main API for
359/// saving / reverting / accepting.
360class Tracker {
361public:
362 enum class TrackerState {
363 Disabled, ///> Tracking is disabled
364 Record, ///> Tracking changes
365 };
366
367private:
368 /// The list of changes that are being tracked.
370 /// The current state of the tracker.
372 Context &Ctx;
373
374public:
375#ifndef NDEBUG
376 /// Helps catch bugs where we are creating new change objects while in the
377 /// middle of creating other change objects.
379#endif // NDEBUG
380
381 explicit Tracker(Context &Ctx) : Ctx(Ctx) {}
382 ~Tracker();
383 Context &getContext() const { return Ctx; }
384 /// Record \p Change and take ownership. This is the main function used to
385 /// track Sandbox IR changes.
386 void track(std::unique_ptr<IRChangeBase> &&Change) {
387 assert(State == TrackerState::Record && "The tracker should be tracking!");
388#ifndef NDEBUG
390 "We are in the middle of creating another change!");
391 if (isTracking())
393#endif // NDEBUG
394 Changes.push_back(std::move(Change));
395
396#ifndef NDEBUG
398#endif
399 }
400 /// A convenience wrapper for `track()` that constructs and tracks the Change
401 /// object if tracking is enabled. \Returns true if tracking is enabled.
402 template <typename ChangeT, typename... ArgsT>
403 bool emplaceIfTracking(ArgsT... Args) {
404 if (!isTracking())
405 return false;
406 track(std::make_unique<ChangeT>(Args...));
407 return true;
408 }
409 /// \Returns true if the tracker is recording changes.
410 bool isTracking() const { return State == TrackerState::Record; }
411 /// \Returns the current state of the tracker.
412 TrackerState getState() const { return State; }
413 /// Turns on IR tracking.
414 void save();
415 /// Stops tracking and accept changes.
416 void accept();
417 /// Stops tracking and reverts to saved state.
418 void revert();
419
420#ifndef NDEBUG
421 void dump(raw_ostream &OS) const;
422 LLVM_DUMP_METHOD void dump() const;
424 Tracker.dump(OS);
425 return OS;
426 }
427#endif // NDEBUG
428};
429
430} // namespace llvm::sandboxir
431
432#endif // LLVM_SANDBOXIR_TRACKER_H
aarch64 promote const
Rewrite undef for PHI
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:533
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define I(x, y, z)
Definition: MD5.cpp:58
mir Rename Register Operands
Module.h This file contains the declarations for the Module class.
This file defines the PointerUnion class, which is a discriminated union of pointer types.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file defines the SmallVector class.
A discriminated union of two or more pointer types, with the discriminator in the low bit of the poin...
Definition: PointerUnion.h:118
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
Contains a list of sandboxir::Instruction's.
Definition: SandboxIR.h:603
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.h:277
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:166
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:274
void dump(raw_ostream &OS) const final
Definition: Tracker.h:276
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:231
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:351
CreateAndInsertInst(Instruction *NewI)
Definition: Tracker.h:349
void dump(raw_ostream &OS) const final
Definition: Tracker.h:353
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:228
void dump(raw_ostream &OS) const final
Definition: Tracker.h:173
void accept() final
This runs when changes get accepted.
Definition: Tracker.cpp:106
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:134
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:111
Similar to GenericSetter but the setters/getters have an index as their first argument.
Definition: Tracker.h:240
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.h:256
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.h:260
void dump(raw_ostream &OS) const final
Definition: Tracker.h:259
GenericSetterWithIdx(InstrT *I, unsigned Idx)
Definition: Tracker.h:254
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:257
This class can be used for tracking most instruction setters.
Definition: Tracker.h:212
void dump(raw_ostream &OS) const final
Definition: Tracker.h:229
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:227
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.h:226
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.h:230
The base class for IR Change classes.
Definition: Tracker.h:67
virtual LLVM_DUMP_METHOD void dump() const =0
virtual void revert(Tracker &Tracker)=0
This runs when changes get reverted.
friend raw_ostream & operator<<(raw_ostream &OS, const IRChangeBase &C)
Definition: Tracker.h:80
virtual ~IRChangeBase()=default
virtual void accept()=0
This runs when changes get accepted.
virtual void dump(raw_ostream &OS) const =0
void dump(raw_ostream &OS) const final
Definition: Tracker.h:340
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:222
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:338
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:217
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition: SandboxIR.h:650
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:211
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:201
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:325
void dump(raw_ostream &OS) const final
Definition: Tracker.h:327
void dump(raw_ostream &OS) const final
Definition: Tracker.h:127
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:69
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:125
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:72
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:111
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:60
void dump(raw_ostream &OS) const final
Definition: Tracker.h:113
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:36
void dump(raw_ostream &OS) const final
Definition: Tracker.h:194
Instruction * getInstruction() const
Definition: Tracker.h:192
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:147
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:191
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:157
SwitchAddCase(SwitchInst *Switch, ConstantInt *Val)
Definition: Tracker.h:289
void dump(raw_ostream &OS) const final
Definition: Tracker.h:294
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:182
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:188
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:292
void dump(raw_ostream &OS) const final
Definition: Tracker.h:310
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:176
SwitchRemoveCase(SwitchInst *Switch, ConstantInt *Val, BasicBlock *Dest)
Definition: Tracker.h:305
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:308
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:173
The tracker collects all the change objects and implements the main API for saving / reverting / acce...
Definition: Tracker.h:360
@ Record
ā€¨Tracking is disabled
void revert()
Stops tracking and reverts to saved state.
Definition: Tracker.cpp:239
TrackerState getState() const
\Returns the current state of the tracker.
Definition: Tracker.h:412
friend raw_ostream & operator<<(raw_ostream &OS, const Tracker &Tracker)
Definition: Tracker.h:423
void dump(raw_ostream &OS) const
Definition: Tracker.cpp:256
bool isTracking() const
\Returns true if the tracker is recording changes.
Definition: Tracker.h:410
void save()
Turns on IR tracking.
Definition: Tracker.cpp:237
Tracker(Context &Ctx)
Definition: Tracker.h:381
void track(std::unique_ptr< IRChangeBase > &&Change)
Record Change and take ownership.
Definition: Tracker.h:386
bool InMiddleOfCreatingChange
Helps catch bugs where we are creating new change objects while in the middle of creating other chang...
Definition: Tracker.h:378
Context & getContext() const
Definition: Tracker.h:383
bool emplaceIfTracking(ArgsT... Args)
A convenience wrapper for track() that constructs and tracks the Change object if tracking is enabled...
Definition: Tracker.h:403
void accept()
Stops tracking and accept changes.
Definition: Tracker.cpp:247
LLVM_DUMP_METHOD void dump() const
Definition: Tracker.cpp:263
Tracks the change of the source Value of a sandboxir::Use.
Definition: Tracker.h:88
UseSet(const Use &U)
Definition: Tracker.h:93
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.h:94
void dump(raw_ostream &OS) const final
Definition: Tracker.h:97
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:95
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:19
Tracks swapping a Use with another Use.
Definition: Tracker.h:133
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.h:142
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:24
void accept() final
This runs when changes get accepted.
Definition: Tracker.h:143
void dump(raw_ostream &OS) const final
Definition: Tracker.h:145
UseSwap(const Use &ThisUse, const Use &OtherUse)
Definition: Tracker.h:138
Represents a Def-use/Use-def edge in SandboxIR.
Definition: Use.h:32
void swap(Use &OtherUse)
Definition: SandboxIR.cpp:27
class User * getUser() const
Definition: Use.h:54
A SandboxIR Value has users. This is the base class.
Definition: SandboxIR.h:205
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ BasicBlock
Various leaf nodes.
Definition: ISDOpcodes.h:71
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163