LLVM: lib/Transforms/Coroutines/MaterializationUtils.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
20#include
21
22using namespace llvm;
23
24using namespace coro;
25
26
27
28#define DEBUG_TYPE "coro-suspend-crossing"
29
30namespace {
31
32
33
34
35
36
37
38struct RematGraph {
39
40
41 struct RematNode {
44 RematNode() = default;
46 };
47
48 RematNode *EntryNode;
49 using RematNodeMap =
51 RematNodeMap Remats;
52 const std::function<bool(Instruction &)> &MaterializableCallback;
54
55 RematGraph(const std::function<bool(Instruction &)> &MaterializableCallback,
57 : MaterializableCallback(MaterializableCallback), Checker(Checker) {
58 std::unique_ptr FirstNode = std::make_unique(I);
59 EntryNode = FirstNode.get();
60 std::deque<std::unique_ptr> WorkList;
61 addNode(std::move(FirstNode), WorkList, cast(I));
62 while (WorkList.size()) {
63 std::unique_ptr N = std::move(WorkList.front());
64 WorkList.pop_front();
65 addNode(std::move(N), WorkList, cast(I));
66 }
67 }
68
69 void addNode(std::unique_ptr NUPtr,
70 std::deque<std::unique_ptr> &WorkList,
71 User *FirstUse) {
72 RematNode *N = NUPtr.get();
73 auto [It, Inserted] = Remats.try_emplace(N->Node);
74 if (!Inserted)
75 return;
76
77
78 It->second = std::move(NUPtr);
79 for (auto &Def : N->Node->operands()) {
81 if ( || !MaterializableCallback(*D) ||
83 continue;
84
85 if (auto It = Remats.find(D); It != Remats.end()) {
86
87 N->Operands.push_back(It->second.get());
88 continue;
89 }
90
91 bool NoMatch = true;
92 for (auto &I : WorkList) {
94 NoMatch = false;
95 N->Operands.push_back(I.get());
96 break;
97 }
98 }
99 if (NoMatch) {
100
101 std::unique_ptr ChildNode = std::make_unique(D);
102 N->Operands.push_back(ChildNode.get());
103 WorkList.push_back(std::move(ChildNode));
104 }
105 }
106 }
107
108#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
113 return;
114 }
115
117 }
118
119 void dump() const {
120 BasicBlock *BB = EntryNode->Node->getParent();
122
125
126 dbgs() << "Entry (";
128 dbgs() << ") : " << *EntryNode->Node << "\n";
129 for (auto &E : Remats) {
130 dbgs() << *(E.first) << "\n";
131 for (RematNode *U : E.second->Operands)
132 dbgs() << " " << *U->Node << "\n";
133 }
134 }
135#endif
136};
137
138}
139
141 using NodeRef = RematGraph::RematNode *;
143
146 return N->Operands.begin();
147 }
149};
150
151
152
153
156 &AllRemats) {
157
158
159
160
161
162 typedef struct {
166 } ProcessNode;
167
169
170 for (const auto &E : AllRemats) {
172 Instruction *CurrentMaterialization = nullptr;
173 RematGraph *RG = E.second.get();
176
177
178
179
180
183 BasicBlock *SuspendPredecessorBlock =
184 Use->getParent()->getSinglePredecessor();
185 assert(SuspendPredecessorBlock && "malformed coro suspend instruction");
187 }
188
189
190
192 ++I;
193 for (; I != RPOT.end(); ++I) {
195 CurrentMaterialization = D->clone();
196 CurrentMaterialization->setName(D->getName());
197 CurrentMaterialization->insertBefore(InsertPoint);
198 InsertPoint = CurrentMaterialization->getIterator();
199
200
201
202 for (auto &I : InstructionsToProcess)
203 I->replaceUsesOfWith(D, CurrentMaterialization);
204
205
206
207
208 for (unsigned i = 0, E = Use->getNumOperands(); i != E; ++i)
209 if (Use->getOperand(i) == D)
210 FinalInstructionsToProcess.push_back(
211 {Use, D, CurrentMaterialization});
212
213 InstructionsToProcess.push_back(CurrentMaterialization);
214 }
215 }
216
217
218 for (auto &R : FinalInstructionsToProcess) {
220 assert(PN->getNumIncomingValues() == 1 && "unexpected number of incoming "
221 "values in the PHINode");
222 PN->replaceAllUsesWith(R.Remat);
223 PN->eraseFromParent();
224 continue;
225 }
226 R.Use->replaceUsesOfWith(R.Def, R.Remat);
227 }
228}
229
230
231
232
237
241
242#ifndef NDEBUG
246 dbgs() << "------------- " << Title << "--------------\n";
247 for (const auto &E : RM) {
248 E.second->dump();
249 dbgs() << "--\n";
250 }
251}
252#endif
253
256 std::function<bool(Instruction &)> IsMaterializable) {
257 if (F.hasOptNone())
258 return;
259
261
262
263
264
266 if (!IsMaterializable(I))
267 continue;
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
289 for (auto &E : Spills) {
291
292
293 auto [It, Inserted] = AllRemats.try_emplace(U);
294 if (!Inserted)
295 continue;
296
297
298 auto RematUPtr =
299 std::make_unique(IsMaterializable, U, Checker);
300
301 LLVM_DEBUG(dbgs() << "***** Next remat group *****\n";
303 for (auto I = RPOT.begin(); I != RPOT.end();
304 ++I) { (*I)->Node->dump(); } dbgs()
305 << "\n";);
306
307 It->second = std::move(RematUPtr);
308 }
309 }
310
311
312
315}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static void rewriteMaterializableInstructions(const SmallMapVector< Instruction *, std::unique_ptr< RematGraph >, 8 > &AllRemats)
Definition MaterializationUtils.cpp:154
static void dumpRemats(StringRef Title, const SmallMapVector< Instruction *, std::unique_ptr< RematGraph >, 8 > &RM)
Definition MaterializationUtils.cpp:243
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Manage lifetime of a slot tracker for printing IR.
int getLocalSlot(const Value *V)
Return the slot number of the specified local value.
void incorporateFunction(const Function &F)
Incorporate the given function.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
bool isDefinitionAcrossSuspend(BasicBlock *DefBB, User *U) const
A Use represents the edge between a Value definition and its users.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
self_iterator getIterator()
SmallMapVector< Value *, SmallVector< Instruction *, 2 >, 8 > SpillInfo
bool defaultMaterializable(Instruction &V)
Default materializable callback.
Definition MaterializationUtils.cpp:233
LLVM_ABI bool isTriviallyMaterializable(Instruction &I)
Definition MaterializationUtils.cpp:238
LLVM_ABI void doRematerializations(Function &F, SuspendCrossingInfo &Checker, std::function< bool(Instruction &)> IsMaterializable)
Definition MaterializationUtils.cpp:254
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
static void dumpBasicBlockLabel(const BasicBlock *BB, ModuleSlotTracker &MST)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
RematGraph::RematNode * NodeRef
Definition MaterializationUtils.cpp:141
static ChildIteratorType child_end(NodeRef N)
Definition MaterializationUtils.cpp:148
RematGraph::RematNode ** ChildIteratorType
Definition MaterializationUtils.cpp:142
static NodeRef getEntryNode(RematGraph *G)
Definition MaterializationUtils.cpp:144
static ChildIteratorType child_begin(NodeRef N)
Definition MaterializationUtils.cpp:145
A MapVector that performs no allocations if smaller than a certain size.