xref: /freebsd/contrib/llvm-project/llvm/lib/SandboxIR/Tracker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
IRChangeBase(Tracker & Parent)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
getIdx() const28 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 
dump() const34 void UseSet::dump() const {
35   dump(dbgs());
36   dbgs() << "\n";
37 }
38 #endif // NDEBUG
39 
~Tracker()40 Tracker::~Tracker() {
41   assert(Changes.empty() && "You must accept or revert changes!");
42 }
43 
EraseFromParent(std::unique_ptr<sandboxir::Value> && ErasedIPtr,Tracker & Tracker)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 
accept()69 void EraseFromParent::accept() {
70   for (const auto &IData : InstrData)
71     IData.LLVMI->deleteValue();
72 }
73 
revert()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
dump() const97 void EraseFromParent::dump() const {
98   dump(dbgs());
99   dbgs() << "\n";
100 }
101 #endif // NDEBUG
102 
RemoveFromParent(Instruction * RemovedI,Tracker & Tracker)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 
revert()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
dump() const121 void RemoveFromParent::dump() const {
122   dump(dbgs());
123   dbgs() << "\n";
124 }
125 #endif
126 
MoveInstr(Instruction * MovedI,Tracker & Tracker)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 
revert()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
dump() const145 void MoveInstr::dump() const {
146   dump(dbgs());
147   dbgs() << "\n";
148 }
149 #endif
150 
track(std::unique_ptr<IRChangeBase> && Change)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 
save()160 void Tracker::save() { State = TrackerState::Record; }
161 
revert()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 
accept()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
dump(raw_ostream & OS) const179 void Tracker::dump(raw_ostream &OS) const {
180   for (const auto &ChangePtr : Changes) {
181     ChangePtr->dump(OS);
182     OS << "\n";
183   }
184 }
dump() const185 void Tracker::dump() const {
186   dump(dbgs());
187   dbgs() << "\n";
188 }
189 #endif // NDEBUG
190