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 PHI is now empty, as we don't need to care about the
99 // order of the incoming values.
100 unsigned NumIncoming = PHI->getNumIncomingValues();
101 if (NumIncoming == 0) {
102 PHI->addIncoming(RemovedV, RemovedBB);
103 return;
104 }
105 // Shift all incoming values by one starting from the end until `Idx`.
106 // Start by adding a copy of the last incoming values.
107 unsigned LastIdx = NumIncoming - 1;
108 PHI->addIncoming(PHI->getIncomingValue(LastIdx),
109 PHI->getIncomingBlock(LastIdx));
110 for (unsigned Idx = LastIdx; Idx > RemovedIdx; --Idx) {
111 auto *PrevV = PHI->getIncomingValue(Idx - 1);
112 auto *PrevBB = PHI->getIncomingBlock(Idx - 1);
113 PHI->setIncomingValue(Idx, PrevV);
114 PHI->setIncomingBlock(Idx, PrevBB);
115 }
116 PHI->setIncomingValue(RemovedIdx, RemovedV);
117 PHI->setIncomingBlock(RemovedIdx, RemovedBB);
118}
119
120#ifndef NDEBUG
122 dump(dbgs());
123 dbgs() << "\n";
124}
125#endif // NDEBUG
126
128 : PHI(PHI), Idx(PHI->getNumIncomingValues()) {}
129
131
132#ifndef NDEBUG
134 dump(dbgs());
135 dbgs() << "\n";
136}
137#endif // NDEBUG
138
140 assert(Changes.empty() && "You must accept or revert changes!");
141}
142
143EraseFromParent::EraseFromParent(std::unique_ptr<sandboxir::Value> &&ErasedIPtr)
144 : ErasedIPtr(std::move(ErasedIPtr)) {
145 auto *I = cast<Instruction>(this->ErasedIPtr.get());
146 auto LLVMInstrs = I->getLLVMInstrs();
147 // Iterate in reverse program order.
148 for (auto *LLVMI : reverse(LLVMInstrs)) {
150 Operands.reserve(LLVMI->getNumOperands());
151 for (auto [OpNum, Use] : enumerate(LLVMI->operands()))
152 Operands.push_back(Use.get());
153 InstrData.push_back({Operands, LLVMI});
154 }
155 assert(is_sorted(InstrData,
156 [](const auto &D0, const auto &D1) {
157 return D0.LLVMI->comesBefore(D1.LLVMI);
158 }) &&
159 "Expected reverse program order!");
160 auto *BotLLVMI = cast<llvm::Instruction>(I->Val);
161 if (BotLLVMI->getNextNode() != nullptr)
162 NextLLVMIOrBB = BotLLVMI->getNextNode();
163 else
164 NextLLVMIOrBB = BotLLVMI->getParent();
165}
166
168 for (const auto &IData : InstrData)
169 IData.LLVMI->deleteValue();
170}
171
173 // Place the bottom-most instruction first.
174 auto [Operands, BotLLVMI] = InstrData[0];
175 if (auto *NextLLVMI = dyn_cast<llvm::Instruction *>(NextLLVMIOrBB)) {
176 BotLLVMI->insertBefore(NextLLVMI->getIterator());
177 } else {
178 auto *LLVMBB = cast<llvm::BasicBlock *>(NextLLVMIOrBB);
179 BotLLVMI->insertInto(LLVMBB, LLVMBB->end());
180 }
181 for (auto [OpNum, Op] : enumerate(Operands))
182 BotLLVMI->setOperand(OpNum, Op);
183
184 // Go over the rest of the instructions and stack them on top.
185 for (auto [Operands, LLVMI] : drop_begin(InstrData)) {
186 LLVMI->insertBefore(BotLLVMI->getIterator());
187 for (auto [OpNum, Op] : enumerate(Operands))
188 LLVMI->setOperand(OpNum, Op);
189 BotLLVMI = LLVMI;
190 }
191 Tracker.getContext().registerValue(std::move(ErasedIPtr));
192}
193
194#ifndef NDEBUG
196 dump(dbgs());
197 dbgs() << "\n";
198}
199#endif // NDEBUG
200
201RemoveFromParent::RemoveFromParent(Instruction *RemovedI) : RemovedI(RemovedI) {
202 if (auto *NextI = RemovedI->getNextNode())
203 NextInstrOrBB = NextI;
204 else
205 NextInstrOrBB = RemovedI->getParent();
206}
207
209 if (auto *NextI = dyn_cast<Instruction *>(NextInstrOrBB)) {
210 RemovedI->insertBefore(NextI);
211 } else {
212 auto *BB = cast<BasicBlock *>(NextInstrOrBB);
213 RemovedI->insertInto(BB, BB->end());
214 }
215}
216
217#ifndef NDEBUG
219 dump(dbgs());
220 dbgs() << "\n";
221}
222#endif
223
225 : CSI(CSI), HandlerIdx(CSI->getNumHandlers()) {}
226
228 // TODO: This should ideally use sandboxir::CatchSwitchInst::removeHandler()
229 // once it gets implemented.
230 auto *LLVMCSI = cast<llvm::CatchSwitchInst>(CSI->Val);
231 LLVMCSI->removeHandler(LLVMCSI->handler_begin() + HandlerIdx);
232}
233
235 for (const auto &C : Switch->cases())
236 Cases.push_back({C.getCaseValue(), C.getCaseSuccessor()});
237}
238
240 // SwitchInst::removeCase doesn't provide any guarantees about the order of
241 // cases after removal. In order to preserve the original ordering, we save
242 // all of them and, when reverting, clear them all then insert them in the
243 // desired order. This still relies on the fact that `addCase` will insert
244 // them at the end, but it is documented to invalidate `case_end()` so it's
245 // probably okay.
246 unsigned NumCases = Switch->getNumCases();
247 for (unsigned I = 0; I < NumCases; ++I)
248 Switch->removeCase(Switch->case_begin());
249 for (auto &Case : Cases)
250 Switch->addCase(Case.Val, Case.Dest);
251}
252
253#ifndef NDEBUG
255 dump(dbgs());
256 dbgs() << "\n";
257}
258#endif // NDEBUG
259
261 auto It = Switch->findCaseValue(Val);
262 Switch->removeCase(It);
263}
264
265#ifndef NDEBUG
267 dump(dbgs());
268 dbgs() << "\n";
269}
270#endif // NDEBUG
271
272MoveInstr::MoveInstr(Instruction *MovedI) : MovedI(MovedI) {
273 if (auto *NextI = MovedI->getNextNode())
274 NextInstrOrBB = NextI;
275 else
276 NextInstrOrBB = MovedI->getParent();
277}
278
280 if (auto *NextI = dyn_cast<Instruction *>(NextInstrOrBB)) {
281 MovedI->moveBefore(NextI);
282 } else {
283 auto *BB = cast<BasicBlock *>(NextInstrOrBB);
284 MovedI->moveBefore(*BB, BB->end());
285 }
286}
287
288#ifndef NDEBUG
289void MoveInstr::dump() const {
290 dump(dbgs());
291 dbgs() << "\n";
292}
293#endif
294
296
297InsertIntoBB::InsertIntoBB(Instruction *InsertedI) : InsertedI(InsertedI) {}
298
299#ifndef NDEBUG
300void InsertIntoBB::dump() const {
301 dump(dbgs());
302 dbgs() << "\n";
303}
304#endif
305
307
308#ifndef NDEBUG
310 dump(dbgs());
311 dbgs() << "\n";
312}
313#endif
314
316 : SVI(SVI), PrevMask(SVI->getShuffleMask()) {}
317
319 SVI->setShuffleMask(PrevMask);
320}
321
322#ifndef NDEBUG
324 dump(dbgs());
325 dbgs() << "\n";
326}
327#endif
328
330
332#ifndef NDEBUG
334 dump(dbgs());
335 dbgs() << "\n";
336}
337#endif
338
340 State = TrackerState::Record;
341#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
342 SnapshotChecker.save();
343#endif
344}
345
347 assert(State == TrackerState::Record && "Forgot to save()!");
349 for (auto &Change : reverse(Changes))
350 Change->revert(*this);
351 Changes.clear();
352#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
353 SnapshotChecker.expectNoDiff();
354#endif
356}
357
359 assert(State == TrackerState::Record && "Forgot to save()!");
361 for (auto &Change : Changes)
362 Change->accept();
363 Changes.clear();
364}
365
366#ifndef NDEBUG
368 for (auto [Idx, ChangePtr] : enumerate(Changes)) {
369 OS << Idx << ". ";
370 ChangePtr->dump(OS);
371 OS << "\n";
372 }
373}
374void Tracker::dump() const {
375 dump(dbgs());
376 dbgs() << "\n";
377}
378#endif // NDEBUG
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Rewrite undef for PHI
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 F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
mir Rename Register Operands
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This class represents an Operation in the Expression.
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:662
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:227
CatchSwitchAddHandler(CatchSwitchInst *CSI)
Definition: Tracker.cpp:224
LLVM_ABI void swapOperands()
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:331
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:333
DenseMap< llvm::Module *, std::unique_ptr< Module > > LLVMModuleToModuleMap
Maps an LLVM Module to the corresponding sandboxir::Module.
Definition: Context.h:85
LLVM_ABI Value * registerValue(std::unique_ptr< Value > &&VPtr)
Take ownership of VPtr and store it in LLVMValueToValueMap.
Definition: Context.cpp:35
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:309
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:306
void accept() final
This runs when changes get accepted.
Definition: Tracker.cpp:167
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:195
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:172
EraseFromParent(std::unique_ptr< sandboxir::Value > &&IPtr)
Definition: Tracker.cpp:143
void expectNoDiff()
Checks current state against saved state, crashes if different.
Definition: Tracker.cpp:72
void save()
Saves a snapshot of the current state.
Definition: Tracker.cpp:70
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:300
InsertIntoBB(Instruction *InsertedI)
Definition: Tracker.cpp:297
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:295
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition: Instruction.h:43
LLVM_ABI void moveBefore(BasicBlock &BB, const BBIterator &WhereIt)
Move this instruction to WhereIt.
LLVM_ABI void insertInto(BasicBlock *BB, const BBIterator &WhereIt)
Insert this detached instruction into BB at WhereIt.
LLVM_ABI Instruction * getNextNode() const
\Returns the next sandboxir::Instruction in the block, or nullptr if at the end of the block.
Definition: Instruction.cpp:43
LLVM_ABI void removeFromParent()
Detach this from its parent BasicBlock without deleting it.
Definition: Instruction.cpp:66
LLVM_ABI void insertBefore(Instruction *BeforeI)
Insert this detached instruction before BeforeI.
LLVM_ABI void eraseFromParent()
Detach this Value from its parent and delete it.
Definition: Instruction.cpp:74
LLVM_ABI BasicBlock * getParent() const
\Returns the BasicBlock containing this Instruction, or null if it is detached.
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:289
MoveInstr(sandboxir::Instruction *I)
Definition: Tracker.cpp:272
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:279
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:130
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:133
unsigned getNumIncomingValues() const
Definition: Instruction.h:2435
LLVM_ABI Value * getIncomingValue(unsigned Idx) const
LLVM_ABI void setIncomingBlock(unsigned Idx, BasicBlock *BB)
LLVM_ABI Value * removeIncomingValue(unsigned Idx)
LLVM_ABI void setIncomingValue(unsigned Idx, Value *V)
LLVM_ABI BasicBlock * getIncomingBlock(unsigned Idx) const
LLVM_ABI void addIncoming(Value *V, BasicBlock *BB)
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:121
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:208
RemoveFromParent(Instruction *RemovedI)
Definition: Tracker.cpp:201
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:218
LLVM_ABI void setShuffleMask(ArrayRef< int > Mask)
ShuffleVectorSetMask(ShuffleVectorInst *SVI)
Definition: Tracker.cpp:315
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:323
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:318
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:260
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:266
CaseIt findCaseValue(const ConstantInt *C)
Definition: Instruction.h:1914
LLVM_ABI void addCase(ConstantInt *OnVal, BasicBlock *Dest)
CaseIt case_begin()
Returns a read/write iterator that points to the first case in the SwitchInst.
Definition: Instruction.h:1897
unsigned getNumCases() const
Definition: Instruction.h:1883
LLVM_ABI CaseIt removeCase(CaseIt It)
This method removes the specified case and its successor from the switch instruction.
LLVM_DUMP_METHOD void dump() const final
Definition: Tracker.cpp:254
SwitchRemoveCase(SwitchInst *Switch)
Definition: Tracker.cpp:234
void revert(Tracker &Tracker) final
This runs when changes get reverted.
Definition: Tracker.cpp:239
The tracker collects all the change objects and implements the main API for saving / reverting / acce...
Definition: Tracker.h:442
@ Record
‍Tracking is disabled
LLVM_ABI void revert()
Stops tracking and reverts to saved state.
Definition: Tracker.cpp:346
LLVM_ABI void save()
Turns on IR tracking.
Definition: Tracker.cpp:339
Context & getContext() const
Definition: Tracker.h:478
LLVM_ABI void accept()
Stops tracking and accept changes.
Definition: Tracker.cpp:358
LLVM_DUMP_METHOD void dump() const
Definition: Tracker.cpp:374
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
llvm::Value * Val
The LLVM Value that corresponds to this SandboxIR Value.
Definition: Value.h:106
#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
@ SS
Definition: X86.h:215
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
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:2491
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
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:1939
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:1886
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:856