LLVM 22.0.0git
Tracker.cpp
Go to the documentation of this file.
1//===- Tracker.cpp --------------------------------------------------------===//
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
10#include "llvm/ADT/STLExtras.h"
11#include "llvm/IR/BasicBlock.h"
12#include "llvm/IR/Instruction.h"
15
16using namespace llvm::sandboxir;
17
18#ifndef NDEBUG
19
20std::string IRSnapshotChecker::dumpIR(const llvm::Function &F) const {
21 std::string Result;
22 raw_string_ostream SS(Result);
23 F.print(SS, /*AssemblyAnnotationWriter=*/nullptr);
24 return Result;
25}
26
27IRSnapshotChecker::ContextSnapshot IRSnapshotChecker::takeSnapshot() const {
28 ContextSnapshot Result;
29 for (const auto &Entry : Ctx.LLVMModuleToModuleMap)
30 for (const auto &F : *Entry.first) {
31 FunctionSnapshot Snapshot;
32 Snapshot.Hash = StructuralHash(F, /*DetailedHash=*/true);
33 Snapshot.TextualIR = dumpIR(F);
34 Result[&F] = Snapshot;
35 }
36 return Result;
37}
38
39bool IRSnapshotChecker::diff(const ContextSnapshot &Orig,
40 const ContextSnapshot &Curr) const {
41 bool DifferenceFound = false;
42 for (const auto &[F, OrigFS] : Orig) {
43 auto CurrFSIt = Curr.find(F);
44 if (CurrFSIt == Curr.end()) {
45 DifferenceFound = true;
46 dbgs() << "Function " << F->getName() << " not found in current IR.\n";
47 dbgs() << OrigFS.TextualIR << "\n";
48 continue;
49 }
50 const FunctionSnapshot &CurrFS = CurrFSIt->second;
51 if (OrigFS.Hash != CurrFS.Hash) {
52 DifferenceFound = true;
53 dbgs() << "Found IR difference in Function " << F->getName() << "\n";
54 dbgs() << "Original:\n" << OrigFS.TextualIR << "\n";
55 dbgs() << "Current:\n" << CurrFS.TextualIR << "\n";
56 }
57 }
58 // Check that Curr doesn't contain any new functions.
59 for (const auto &[F, CurrFS] : Curr) {
60 if (!Orig.contains(F)) {
61 DifferenceFound = true;
62 dbgs() << "Function " << F->getName()
63 << " found in current IR but not in original snapshot.\n";
64 dbgs() << CurrFS.TextualIR << "\n";
65 }
66 }
67 return DifferenceFound;
68}
69
70void IRSnapshotChecker::save() { OrigContextSnapshot = takeSnapshot(); }
71
73 ContextSnapshot CurrContextSnapshot = takeSnapshot();
74 if (diff(OrigContextSnapshot, CurrContextSnapshot)) {
76 "Original and current IR differ! Probably a checkpointing bug.");
77 }
78}
79
80void UseSet::dump() const {
81 dump(dbgs());
82 dbgs() << "\n";
83}
84
85void UseSwap::dump() const {
86 dump(dbgs());
87 dbgs() << "\n";
88}
89#endif // NDEBUG
90
92 : PHI(PHI), RemovedIdx(RemovedIdx) {
93 RemovedV = PHI->getIncomingValue(RemovedIdx);
94 RemovedBB = PHI->getIncomingBlock(RemovedIdx);
95}
96
98 // Special case: if the removed incoming value is the last.
99 unsigned NumIncoming = PHI->getNumIncomingValues();
100 if (NumIncoming == RemovedIdx) {
101 PHI->addIncoming(RemovedV, RemovedBB);
102 return;
103 }
104 // Move the incoming value currently at `RemovedIdx` to the end, restore the
105 // old incoming value back to `RemovedIdx`.
106 PHI->addIncoming(PHI->getIncomingValue(RemovedIdx),
107 PHI->getIncomingBlock(RemovedIdx));
108 PHI->setIncomingValue(RemovedIdx, RemovedV);
109 PHI->setIncomingBlock(RemovedIdx, RemovedBB);
110}
111
112#ifndef NDEBUG
114 dump(dbgs());
115 dbgs() << "\n";
116}
117#endif // NDEBUG
118
120 : PHI(PHI), Idx(PHI->getNumIncomingValues()) {}
121
122void PHIAddIncoming::revert(Tracker &Tracker) { PHI->removeIncomingValue(Idx); }
123
124#ifndef NDEBUG
126 dump(dbgs());
127 dbgs() << "\n";
128}
129#endif // NDEBUG
130
132 assert(Changes.empty() && "You must accept or revert changes!");
133}
134
135EraseFromParent::EraseFromParent(std::unique_ptr<sandboxir::Value> &&ErasedIPtr)
136 : ErasedIPtr(std::move(ErasedIPtr)) {
137 auto *I = cast<Instruction>(this->ErasedIPtr.get());
138 auto LLVMInstrs = I->getLLVMInstrs();
139 // Iterate in reverse program order.
140 for (auto *LLVMI : reverse(LLVMInstrs)) {
142 Operands.reserve(LLVMI->getNumOperands());
143 for (auto [OpNum, Use] : enumerate(LLVMI->operands()))
144 Operands.push_back(Use.get());
145 InstrData.push_back({Operands, LLVMI});
146 }
147 assert(is_sorted(InstrData,
148 [](const auto &D0, const auto &D1) {
149 return D0.LLVMI->comesBefore(D1.LLVMI);
150 }) &&
151 "Expected reverse program order!");
152 auto *BotLLVMI = cast<llvm::Instruction>(I->Val);
153 if (BotLLVMI->getNextNode() != nullptr)
154 NextLLVMIOrBB = BotLLVMI->getNextNode();
155 else
156 NextLLVMIOrBB = BotLLVMI->getParent();
157}
158
160 for (const auto &IData : InstrData)
161 IData.LLVMI->deleteValue();
162}
163
165 // Place the bottom-most instruction first.
166 auto [Operands, BotLLVMI] = InstrData[0];
167 if (auto *NextLLVMI = dyn_cast<llvm::Instruction *>(NextLLVMIOrBB)) {
168 BotLLVMI->insertBefore(NextLLVMI->getIterator());
169 } else {
170 auto *LLVMBB = cast<llvm::BasicBlock *>(NextLLVMIOrBB);
171 BotLLVMI->insertInto(LLVMBB, LLVMBB->end());
172 }
173 for (auto [OpNum, Op] : enumerate(Operands))
174 BotLLVMI->setOperand(OpNum, Op);
175
176 // Go over the rest of the instructions and stack them on top.
177 for (auto [Operands, LLVMI] : drop_begin(InstrData)) {
178 LLVMI->insertBefore(BotLLVMI->getIterator());
179 for (auto [OpNum, Op] : enumerate(Operands))
180 LLVMI->setOperand(OpNum, Op);
181 BotLLVMI = LLVMI;
182 }
183 Tracker.getContext().registerValue(std::move(ErasedIPtr));
184}
185
186#ifndef NDEBUG
188 dump(dbgs());
189 dbgs() << "\n";
190}
191#endif // NDEBUG
192
193RemoveFromParent::RemoveFromParent(Instruction *RemovedI) : RemovedI(RemovedI) {
194 if (auto *NextI = RemovedI->getNextNode())
195 NextInstrOrBB = NextI;
196 else
197 NextInstrOrBB = RemovedI->getParent();
198}
199
201 if (auto *NextI = dyn_cast<Instruction *>(NextInstrOrBB)) {
202 RemovedI->insertBefore(NextI);
203 } else {
204 auto *BB = cast<BasicBlock *>(NextInstrOrBB);
205 RemovedI->insertInto(BB, BB->end());
206 }
207}
208
209#ifndef NDEBUG
211 dump(dbgs());
212 dbgs() << "\n";
213}
214#endif
215
217 : CSI(CSI), HandlerIdx(CSI->getNumHandlers()) {}
218
220 // TODO: This should ideally use sandboxir::CatchSwitchInst::removeHandler()
221 // once it gets implemented.
222 auto *LLVMCSI = cast<llvm::CatchSwitchInst>(CSI->Val);
223 LLVMCSI->removeHandler(LLVMCSI->handler_begin() + HandlerIdx);
224}
225
227 for (const auto &C : Switch->cases())
228 Cases.push_back({C.getCaseValue(), C.getCaseSuccessor()});
229}
230
232 // SwitchInst::removeCase doesn't provide any guarantees about the order of
233 // cases after removal. In order to preserve the original ordering, we save
234 // all of them and, when reverting, clear them all then insert them in the
235 // desired order. This still relies on the fact that `addCase` will insert
236 // them at the end, but it is documented to invalidate `case_end()` so it's
237 // probably okay.
238 unsigned NumCases = Switch->getNumCases();
239 for (unsigned I = 0; I < NumCases; ++I)
240 Switch->removeCase(Switch->case_begin());
241 for (auto &Case : Cases)
242 Switch->addCase(Case.Val, Case.Dest);
243}
244
245#ifndef NDEBUG
247 dump(dbgs());
248 dbgs() << "\n";
249}
250#endif // NDEBUG
251
253 auto It = Switch->findCaseValue(Val);
254 Switch->removeCase(It);
255}
256
257#ifndef NDEBUG
259 dump(dbgs());
260 dbgs() << "\n";
261}
262#endif // NDEBUG
263
264MoveInstr::MoveInstr(Instruction *MovedI) : MovedI(MovedI) {
265 if (auto *NextI = MovedI->getNextNode())
266 NextInstrOrBB = NextI;
267 else
268 NextInstrOrBB = MovedI->getParent();
269}
270
272 if (auto *NextI = dyn_cast<Instruction *>(NextInstrOrBB)) {
273 MovedI->moveBefore(NextI);
274 } else {
275 auto *BB = cast<BasicBlock *>(NextInstrOrBB);
276 MovedI->moveBefore(*BB, BB->end());
277 }
278}
279
280#ifndef NDEBUG
281void MoveInstr::dump() const {
282 dump(dbgs());
283 dbgs() << "\n";
284}
285#endif
286
287void InsertIntoBB::revert(Tracker &Tracker) { InsertedI->removeFromParent(); }
288
289InsertIntoBB::InsertIntoBB(Instruction *InsertedI) : InsertedI(InsertedI) {}
290
291#ifndef NDEBUG
292void InsertIntoBB::dump() const {
293 dump(dbgs());
294 dbgs() << "\n";
295}
296#endif
297
298void CreateAndInsertInst::revert(Tracker &Tracker) { NewI->eraseFromParent(); }
299
300#ifndef NDEBUG
302 dump(dbgs());
303 dbgs() << "\n";
304}
305#endif
306
308 : SVI(SVI), PrevMask(SVI->getShuffleMask()) {}
309
311 SVI->setShuffleMask(PrevMask);
312}
313
314#ifndef NDEBUG
316 dump(dbgs());
317 dbgs() << "\n";
318}
319#endif
320
322
323void CmpSwapOperands::revert(Tracker &Tracker) { Cmp->swapOperands(); }
324#ifndef NDEBUG
326 dump(dbgs());
327 dbgs() << "\n";
328}
329#endif
330
332 State = TrackerState::Record;
333#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
334 SnapshotChecker.save();
335#endif
336}
337
339 assert(State == TrackerState::Record && "Forgot to save()!");
341 for (auto &Change : reverse(Changes))
342 Change->revert(*this);
343 Changes.clear();
344#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
345 SnapshotChecker.expectNoDiff();
346#endif
348}
349
351 assert(State == TrackerState::Record && "Forgot to save()!");
353 for (auto &Change : Changes)
354 Change->accept();
355 Changes.clear();
356}
357
358#ifndef NDEBUG
359void Tracker::dump(raw_ostream &OS) const {
360 for (auto [Idx, ChangePtr] : enumerate(Changes)) {
361 OS << Idx << ". ";
362 ChangePtr->dump(OS);
363 OS << "\n";
364 }
365}
366void Tracker::dump() const {
367 dump(dbgs());
368 dbgs() << "\n";
369}
370#endif // NDEBUG
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file contains some templates that are useful if you are working with the STL at all.
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:219
CatchSwitchAddHandler(CatchSwitchInst *CSI)
Definition Tracker.cpp:216
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:323
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:325
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:301
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:298
void accept() final
This runs when changes get accepted.
Definition Tracker.cpp:159
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:187
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:164
EraseFromParent(std::unique_ptr< sandboxir::Value > &&IPtr)
Definition Tracker.cpp:135
LLVM_ABI_FOR_TEST void expectNoDiff()
Checks current state against saved state, crashes if different.
Definition Tracker.cpp:72
LLVM_ABI_FOR_TEST void save()
Saves a snapshot of the current state.
Definition Tracker.cpp:70
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:292
InsertIntoBB(Instruction *InsertedI)
Definition Tracker.cpp:289
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:287
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:281
MoveInstr(sandboxir::Instruction *I)
Definition Tracker.cpp:264
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:271
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:122
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:125
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:113
PHIRemoveIncoming(PHINode *PHI, unsigned RemovedIdx)
Definition Tracker.cpp:91
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:97
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:200
RemoveFromParent(Instruction *RemovedI)
Definition Tracker.cpp:193
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:210
ShuffleVectorSetMask(ShuffleVectorInst *SVI)
Definition Tracker.cpp:307
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:315
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:310
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:252
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:258
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:246
SwitchRemoveCase(SwitchInst *Switch)
Definition Tracker.cpp:226
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition Tracker.cpp:231
LLVM_ABI void revert()
Stops tracking and reverts to saved state.
Definition Tracker.cpp:338
LLVM_ABI void save()
Turns on IR tracking.
Definition Tracker.cpp:331
LLVM_ABI void accept()
Stops tracking and accept changes.
Definition Tracker.cpp:350
LLVM_DUMP_METHOD void dump() const
Definition Tracker.cpp:366
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:80
LLVM_DUMP_METHOD void dump() const final
Definition Tracker.cpp:85
Represents a Def-use/Use-def edge in SandboxIR.
Definition Use.h:33
LLVM_ABI Value * get() const
Definition Use.cpp:15
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2503
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
Definition STLExtras.h:1941
DWARFExpression::Operation Op
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1888
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI stable_hash StructuralHash(const Function &F, bool DetailedHash=false)
Returns a hash of the function F.
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870