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 9 #include "llvm/SandboxIR/Tracker.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/IR/BasicBlock.h" 12 #include "llvm/IR/Instruction.h" 13 #include "llvm/SandboxIR/SandboxIR.h" 14 #include <sstream> 15 16 using namespace llvm::sandboxir; 17 18 IRChangeBase::IRChangeBase(Tracker &Parent) : Parent(Parent) { 19 #ifndef NDEBUG 20 assert(!Parent.InMiddleOfCreatingChange && 21 "We are in the middle of creating another change!"); 22 if (Parent.isTracking()) 23 Parent.InMiddleOfCreatingChange = true; 24 #endif // NDEBUG 25 } 26 27 #ifndef NDEBUG 28 unsigned IRChangeBase::getIdx() const { 29 auto It = 30 find_if(Parent.Changes, [this](auto &Ptr) { return Ptr.get() == this; }); 31 return It - Parent.Changes.begin(); 32 } 33 34 void UseSet::dump() const { 35 dump(dbgs()); 36 dbgs() << "\n"; 37 } 38 #endif // NDEBUG 39 40 Tracker::~Tracker() { 41 assert(Changes.empty() && "You must accept or revert changes!"); 42 } 43 44 EraseFromParent::EraseFromParent(std::unique_ptr<sandboxir::Value> &&ErasedIPtr, 45 Tracker &Tracker) 46 : IRChangeBase(Tracker), ErasedIPtr(std::move(ErasedIPtr)) { 47 auto *I = cast<Instruction>(this->ErasedIPtr.get()); 48 auto LLVMInstrs = I->getLLVMInstrs(); 49 // Iterate in reverse program order. 50 for (auto *LLVMI : reverse(LLVMInstrs)) { 51 SmallVector<llvm::Value *> Operands; 52 Operands.reserve(LLVMI->getNumOperands()); 53 for (auto [OpNum, Use] : enumerate(LLVMI->operands())) 54 Operands.push_back(Use.get()); 55 InstrData.push_back({Operands, LLVMI}); 56 } 57 assert(is_sorted(InstrData, 58 [](const auto &D0, const auto &D1) { 59 return D0.LLVMI->comesBefore(D1.LLVMI); 60 }) && 61 "Expected reverse program order!"); 62 auto *BotLLVMI = cast<llvm::Instruction>(I->Val); 63 if (BotLLVMI->getNextNode() != nullptr) 64 NextLLVMIOrBB = BotLLVMI->getNextNode(); 65 else 66 NextLLVMIOrBB = BotLLVMI->getParent(); 67 } 68 69 void EraseFromParent::accept() { 70 for (const auto &IData : InstrData) 71 IData.LLVMI->deleteValue(); 72 } 73 74 void EraseFromParent::revert() { 75 // Place the bottom-most instruction first. 76 auto [Operands, BotLLVMI] = InstrData[0]; 77 if (auto *NextLLVMI = NextLLVMIOrBB.dyn_cast<llvm::Instruction *>()) { 78 BotLLVMI->insertBefore(NextLLVMI); 79 } else { 80 auto *LLVMBB = NextLLVMIOrBB.get<llvm::BasicBlock *>(); 81 BotLLVMI->insertInto(LLVMBB, LLVMBB->end()); 82 } 83 for (auto [OpNum, Op] : enumerate(Operands)) 84 BotLLVMI->setOperand(OpNum, Op); 85 86 // Go over the rest of the instructions and stack them on top. 87 for (auto [Operands, LLVMI] : drop_begin(InstrData)) { 88 LLVMI->insertBefore(BotLLVMI); 89 for (auto [OpNum, Op] : enumerate(Operands)) 90 LLVMI->setOperand(OpNum, Op); 91 BotLLVMI = LLVMI; 92 } 93 Parent.getContext().registerValue(std::move(ErasedIPtr)); 94 } 95 96 #ifndef NDEBUG 97 void EraseFromParent::dump() const { 98 dump(dbgs()); 99 dbgs() << "\n"; 100 } 101 #endif // NDEBUG 102 103 RemoveFromParent::RemoveFromParent(Instruction *RemovedI, Tracker &Tracker) 104 : IRChangeBase(Tracker), RemovedI(RemovedI) { 105 if (auto *NextI = RemovedI->getNextNode()) 106 NextInstrOrBB = NextI; 107 else 108 NextInstrOrBB = RemovedI->getParent(); 109 } 110 111 void RemoveFromParent::revert() { 112 if (auto *NextI = NextInstrOrBB.dyn_cast<Instruction *>()) { 113 RemovedI->insertBefore(NextI); 114 } else { 115 auto *BB = NextInstrOrBB.get<BasicBlock *>(); 116 RemovedI->insertInto(BB, BB->end()); 117 } 118 } 119 120 #ifndef NDEBUG 121 void RemoveFromParent::dump() const { 122 dump(dbgs()); 123 dbgs() << "\n"; 124 } 125 #endif 126 127 MoveInstr::MoveInstr(Instruction *MovedI, Tracker &Tracker) 128 : IRChangeBase(Tracker), MovedI(MovedI) { 129 if (auto *NextI = MovedI->getNextNode()) 130 NextInstrOrBB = NextI; 131 else 132 NextInstrOrBB = MovedI->getParent(); 133 } 134 135 void MoveInstr::revert() { 136 if (auto *NextI = NextInstrOrBB.dyn_cast<Instruction *>()) { 137 MovedI->moveBefore(NextI); 138 } else { 139 auto *BB = NextInstrOrBB.get<BasicBlock *>(); 140 MovedI->moveBefore(*BB, BB->end()); 141 } 142 } 143 144 #ifndef NDEBUG 145 void MoveInstr::dump() const { 146 dump(dbgs()); 147 dbgs() << "\n"; 148 } 149 #endif 150 151 void Tracker::track(std::unique_ptr<IRChangeBase> &&Change) { 152 assert(State == TrackerState::Record && "The tracker should be tracking!"); 153 Changes.push_back(std::move(Change)); 154 155 #ifndef NDEBUG 156 InMiddleOfCreatingChange = false; 157 #endif 158 } 159 160 void Tracker::save() { State = TrackerState::Record; } 161 162 void Tracker::revert() { 163 assert(State == TrackerState::Record && "Forgot to save()!"); 164 State = TrackerState::Disabled; 165 for (auto &Change : reverse(Changes)) 166 Change->revert(); 167 Changes.clear(); 168 } 169 170 void Tracker::accept() { 171 assert(State == TrackerState::Record && "Forgot to save()!"); 172 State = TrackerState::Disabled; 173 for (auto &Change : Changes) 174 Change->accept(); 175 Changes.clear(); 176 } 177 178 #ifndef NDEBUG 179 void Tracker::dump(raw_ostream &OS) const { 180 for (const auto &ChangePtr : Changes) { 181 ChangePtr->dump(OS); 182 OS << "\n"; 183 } 184 } 185 void Tracker::dump() const { 186 dump(dbgs()); 187 dbgs() << "\n"; 188 } 189 #endif // NDEBUG 190