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
IRChangeBase(Tracker & Parent)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
getIdx() const28*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
dump() const34*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
~Tracker()40*0fca6ea1SDimitry Andric Tracker::~Tracker() {
41*0fca6ea1SDimitry Andric assert(Changes.empty() && "You must accept or revert changes!");
42*0fca6ea1SDimitry Andric }
43*0fca6ea1SDimitry Andric
EraseFromParent(std::unique_ptr<sandboxir::Value> && ErasedIPtr,Tracker & Tracker)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
accept()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
revert()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
dump() const97*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
RemoveFromParent(Instruction * RemovedI,Tracker & Tracker)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
revert()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
dump() const121*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
MoveInstr(Instruction * MovedI,Tracker & Tracker)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
revert()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
dump() const145*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
track(std::unique_ptr<IRChangeBase> && Change)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
save()160*0fca6ea1SDimitry Andric void Tracker::save() { State = TrackerState::Record; }
161*0fca6ea1SDimitry Andric
revert()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
accept()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
dump(raw_ostream & OS) const179*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 }
dump() const185*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