22 raw_string_ostream
SS(Result);
27IRSnapshotChecker::ContextSnapshot IRSnapshotChecker::takeSnapshot()
const {
29 for (
const auto &Entry : Ctx.LLVMModuleToModuleMap)
30 for (
const auto &
F : *
Entry.first) {
31 FunctionSnapshot Snapshot;
33 Snapshot.TextualIR = dumpIR(
F);
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";
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";
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";
67 return DifferenceFound;
73 ContextSnapshot CurrContextSnapshot = takeSnapshot();
74 if (diff(OrigContextSnapshot, CurrContextSnapshot)) {
76 "Original and current IR differ! Probably a checkpointing bug.");
92 : PHI(PHI), RemovedIdx(RemovedIdx) {
93 RemovedV = PHI->getIncomingValue(RemovedIdx);
94 RemovedBB = PHI->getIncomingBlock(RemovedIdx);
99 unsigned NumIncoming = PHI->getNumIncomingValues();
100 if (NumIncoming == RemovedIdx) {
101 PHI->addIncoming(RemovedV, RemovedBB);
106 PHI->addIncoming(PHI->getIncomingValue(RemovedIdx),
107 PHI->getIncomingBlock(RemovedIdx));
108 PHI->setIncomingValue(RemovedIdx, RemovedV);
109 PHI->setIncomingBlock(RemovedIdx, RemovedBB);
120 : PHI(PHI), Idx(PHI->getNumIncomingValues()) {}
132 assert(Changes.empty() &&
"You must accept or revert changes!");
136 : ErasedIPtr(
std::
move(ErasedIPtr)) {
138 auto LLVMInstrs =
I->getLLVMInstrs();
140 for (
auto *LLVMI :
reverse(LLVMInstrs)) {
142 Operands.
reserve(LLVMI->getNumOperands());
145 InstrData.push_back({Operands, LLVMI});
148 [](
const auto &D0,
const auto &D1) {
149 return D0.LLVMI->comesBefore(D1.LLVMI);
151 "Expected reverse program order!");
153 if (BotLLVMI->getNextNode() !=
nullptr)
154 NextLLVMIOrBB = BotLLVMI->getNextNode();
156 NextLLVMIOrBB = BotLLVMI->getParent();
160 for (
const auto &IData : InstrData)
161 IData.LLVMI->deleteValue();
166 auto [Operands, BotLLVMI] = InstrData[0];
168 BotLLVMI->insertBefore(NextLLVMI->getIterator());
171 BotLLVMI->insertInto(LLVMBB, LLVMBB->end());
174 BotLLVMI->setOperand(OpNum,
Op);
177 for (
auto [Operands, LLVMI] :
drop_begin(InstrData)) {
178 LLVMI->insertBefore(BotLLVMI->getIterator());
180 LLVMI->setOperand(OpNum,
Op);
183 Tracker.getContext().registerValue(std::move(ErasedIPtr));
194 if (
auto *NextI = RemovedI->getNextNode())
195 NextInstrOrBB = NextI;
197 NextInstrOrBB = RemovedI->getParent();
202 RemovedI->insertBefore(NextI);
205 RemovedI->insertInto(BB, BB->end());
217 : CSI(CSI), HandlerIdx(CSI->getNumHandlers()) {}
223 LLVMCSI->removeHandler(LLVMCSI->handler_begin() + HandlerIdx);
227 for (
const auto &
C : Switch->cases())
228 Cases.push_back({C.getCaseValue(), C.getCaseSuccessor()});
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);
253 auto It = Switch->findCaseValue(Val);
254 Switch->removeCase(It);
265 if (
auto *NextI = MovedI->getNextNode())
266 NextInstrOrBB = NextI;
268 NextInstrOrBB = MovedI->getParent();
273 MovedI->moveBefore(NextI);
276 MovedI->moveBefore(*BB, BB->end());
308 : SVI(SVI), PrevMask(SVI->getShuffleMask()) {}
311 SVI->setShuffleMask(PrevMask);
333#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
334 SnapshotChecker.save();
341 for (
auto &Change :
reverse(Changes))
342 Change->revert(*
this);
344#if !defined(NDEBUG) && defined(EXPENSIVE_CHECKS)
345 SnapshotChecker.expectNoDiff();
353 for (
auto &Change : Changes)
360 for (
auto [Idx, ChangePtr] :
enumerate(Changes)) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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.
void revert(Tracker &Tracker) final
This runs when changes get reverted.
CatchSwitchAddHandler(CatchSwitchInst *CSI)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
CmpSwapOperands(CmpInst *Cmp)
LLVM_DUMP_METHOD void dump() const final
LLVM_DUMP_METHOD void dump() const final
void revert(Tracker &Tracker) final
This runs when changes get reverted.
void accept() final
This runs when changes get accepted.
LLVM_DUMP_METHOD void dump() const final
void revert(Tracker &Tracker) final
This runs when changes get reverted.
EraseFromParent(std::unique_ptr< sandboxir::Value > &&IPtr)
LLVM_ABI_FOR_TEST void expectNoDiff()
Checks current state against saved state, crashes if different.
LLVM_ABI_FOR_TEST void save()
Saves a snapshot of the current state.
LLVM_DUMP_METHOD void dump() const final
InsertIntoBB(Instruction *InsertedI)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
LLVM_DUMP_METHOD void dump() const final
MoveInstr(sandboxir::Instruction *I)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
PHIAddIncoming(PHINode *PHI)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
LLVM_DUMP_METHOD void dump() const final
LLVM_DUMP_METHOD void dump() const final
PHIRemoveIncoming(PHINode *PHI, unsigned RemovedIdx)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
void revert(Tracker &Tracker) final
This runs when changes get reverted.
RemoveFromParent(Instruction *RemovedI)
LLVM_DUMP_METHOD void dump() const final
ShuffleVectorSetMask(ShuffleVectorInst *SVI)
LLVM_DUMP_METHOD void dump() const final
void revert(Tracker &Tracker) final
This runs when changes get reverted.
void revert(Tracker &Tracker) final
This runs when changes get reverted.
LLVM_DUMP_METHOD void dump() const final
LLVM_DUMP_METHOD void dump() const final
SwitchRemoveCase(SwitchInst *Switch)
void revert(Tracker &Tracker) final
This runs when changes get reverted.
LLVM_ABI void revert()
Stops tracking and reverts to saved state.
LLVM_ABI void save()
Turns on IR tracking.
LLVM_ABI void accept()
Stops tracking and accept changes.
LLVM_DUMP_METHOD void dump() const
LLVM_DUMP_METHOD void dump() const final
LLVM_DUMP_METHOD void dump() const final
Represents a Def-use/Use-def edge in SandboxIR.
LLVM_ABI Value * get() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
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.