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