LLVM 24.0.0git
Scheduler.cpp
Go to the documentation of this file.
1//===- Scheduler.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
11
12namespace llvm::sandboxir {
13
14// TODO: Check if we can cache top/bottom to reduce compile-time.
16 DGNode *TopN = Nodes.front();
17 for (auto *N : drop_begin(Nodes)) {
18 if (N->getInstruction()->comesBefore(TopN->getInstruction()))
19 TopN = N;
20 }
21 return TopN;
22}
23
25 DGNode *BotN = Nodes.front();
26 for (auto *N : drop_begin(Nodes)) {
27 if (BotN->getInstruction()->comesBefore(N->getInstruction()))
28 BotN = N;
29 }
30 return BotN;
31}
32
34 for (auto *N : Nodes) {
35 auto *I = N->getInstruction();
36 if (I->getIterator() == Where)
37 ++Where; // Try to maintain bundle order.
38 I->moveBefore(*Where.getNodeParent(), Where);
39 }
40}
41
42#ifndef NDEBUG
44 for (auto *N : Nodes)
45 OS << *N;
46}
47
48void SchedBundle::dump() const {
49 dump(dbgs());
50 dbgs() << "\n";
51}
52#endif // NDEBUG
53
54#ifndef NDEBUG
56 auto ListCopy = List;
57 while (!ListCopy.empty()) {
58 OS << *ListCopy.top() << "\n";
59 ListCopy.pop();
60 }
61}
62
64 dump(dbgs());
65 dbgs() << "\n";
66}
67
70 OS << "Before begin of BB " << BB->getName();
71 else if (BasicBlock *BB = atEndOrNull())
72 OS << "At end of BB " << BB->getName();
73 else
74 OS << "At instr: " << *atInstrOrNull();
75}
76
78 print(dbgs());
79 dbgs() << "\n";
80}
81#endif // NDEBUG
82
83void Scheduler::scheduleAndUpdateReadyList(SchedBundle &Bndl) {
84 // Find where we should schedule the instructions.
85 assert(ScheduleFrontierOpt && "Should have been set by now!");
86 auto Where = Dir == SchedDirection::BottomUp
87 ? ScheduleFrontierOpt->getIterator()
88 : ScheduleFrontierOpt->getNext().getIterator();
89 // Move all instructions in `Bndl` to `Where`.
90 Bndl.cluster(Where);
91 // Update the last scheduled bundle.
92 ScheduleFrontierOpt = Dir == SchedDirection::BottomUp
93 ? Bndl.getTop()->getInstruction()->getIterator()
94 : Bndl.getBot()->getInstruction()->getIterator();
95 // Set nodes as "scheduled" and decrement the UnscheduledSuccs/Preds counter
96 // of all dependency predecessors/successors.
97 for (DGNode *N : Bndl) {
98 switch (Dir) {
100 for (auto *DepN : N->preds(DAG)) {
101 DepN->decrUnscheduledDeps();
102 if (DepN->ready() && !DepN->scheduled())
103 ReadyList.insert(DepN);
104 }
105 break;
106 }
108 for (auto *DepN : N->succs(DAG)) {
109 DepN->decrUnscheduledDeps();
110 if (DepN->ready() && !DepN->scheduled())
111 ReadyList.insert(DepN);
112 }
113 break;
114 }
115 }
116 N->setScheduled();
117 }
118}
119
120void Scheduler::notifyCreateInstrBeforeDAGUpdates(DGNode *N) {
121 Instruction *I = N->getInstruction();
122 // If the instruction is inserted below the top-of-schedule then we mark it as
123 // "scheduled".
124 bool IsScheduled =
125 ScheduleFrontierOpt &&
126 ScheduleFrontierOpt->getIterator() != I->getParent()->end() &&
127 ((Dir == SchedDirection::BottomUp &&
128 (*ScheduleFrontierOpt.value()).comesBefore(I)) ||
129 (Dir == SchedDirection::TopDown &&
130 I->comesBefore(&*ScheduleFrontierOpt.value())));
131 if (IsScheduled)
132 N->setScheduled();
133}
134
135void Scheduler::notifyCreateInstrAfterDAGUpdates(DGNode *N) {
136 // If the new instruction is above the top of schedule we need to remove its
137 // dependency predecessors from the ready list and increment their
138 // `UnscheduledDeps` counters.
139 if (!N->scheduled()) {
140 if (Dir == SchedDirection::BottomUp) {
141 for (auto *PredN : N->preds(DAG)) {
142 ReadyList.remove(PredN);
143 PredN->incrUnscheduledDeps();
144 }
145 } else {
146 for (auto *SuccN : N->succs(DAG)) {
147 ReadyList.remove(SuccN);
148 SuccN->incrUnscheduledDeps();
149 }
150 }
151 }
152}
153
154void Scheduler::notifyEraseInstr(Instruction *I) {
155 // We don't maintain the state while reverting.
156 if (Ctx.getTracker().getState() == Tracker::TrackerState::Reverting)
157 return;
158 auto *N = DAG.getNode(I);
159 if (N == nullptr)
160 return;
161 ReadyList.remove(N);
162 // Also decrement the unscheduledDep counter for the dependents and add them
163 // to the ready list if they become ready.
164 auto UpdateNodeAndTryAddToReadyList = [this, N](DGNode *DepN) {
165 if (DepN->scheduled())
166 return;
167 if (!N->scheduled() && !DepN->ready())
168 DepN->decrUnscheduledDeps();
169 if (DepN->ready() && !ReadyList.contains(DepN))
170 ReadyList.insert(DepN);
171 };
172 if (Dir == SchedDirection::BottomUp) {
173 for (auto *DepN : N->preds(DAG))
174 UpdateNodeAndTryAddToReadyList(DepN);
175 } else if (Dir == SchedDirection::TopDown) {
176 for (auto *DepN : N->succs(DAG))
177 UpdateNodeAndTryAddToReadyList(DepN);
178 }
179}
180
181void Scheduler::notifyMoveInstr(Instruction *I, const BBIterator &To) {
182 // We don't maintain the state while reverting.
183 if (Ctx.getTracker().getState() == Tracker::TrackerState::Reverting)
184 return;
185 // We assume that the dependencies have not changed because the user will
186 // only attempt instruction moves that don't modify the dependencies, because
187 // if they did they would not be legal.
188 //
189 // If this assumption does not hold, we would need to empty the ready list and
190 // re-fill it.
191}
192void Scheduler::notifySetUse(const Use &U, Value *NewSrc) {
193 // We don't maintain the state while reverting.
194 if (Ctx.getTracker().getState() == Tracker::TrackerState::Reverting)
195 return;
196 Instruction *DstI = cast<Instruction>(U.getUser());
197 DGNode *DstN = DAG.getNode(DstI);
198 Value *OldSrc = U.get();
199 DGNode *OldSrcN = isa<Instruction>(OldSrc)
200 ? DAG.getNode(cast<Instruction>(OldSrc))
201 : nullptr;
202 DGNode *NewSrcN = isa<Instruction>(NewSrc)
203 ? DAG.getNode(cast<Instruction>(NewSrc))
204 : nullptr;
205 switch (Dir) {
207 // Check if OldSrc is now ready and add it to the ready list.
208 if (OldSrcN && OldSrcN->ready() && !OldSrcN->scheduled() &&
209 !ReadyList.contains(OldSrcN))
210 ReadyList.insert(OldSrcN);
211 // Check if NewSrcN needs to be removed from the ready list.
212 if (NewSrcN && (!DstN || !DstN->scheduled()) && !NewSrcN->ready())
213 ReadyList.remove(NewSrcN);
214 break;
215 }
217 // Check if we need to add DstN to the ready list.
218 if (DstN && DstN->ready() && !NewSrcN->scheduled() &&
219 !ReadyList.contains(NewSrcN))
220 ReadyList.insert(NewSrcN);
221 // Check if we need to remove DstN from the ready list.
222 if (DstN && !DstN->ready())
223 ReadyList.remove(NewSrcN);
224 break;
225 }
226 }
227}
228
229SchedBundle *Scheduler::createBundle(ArrayRef<Instruction *> Instrs) {
231 Nodes.reserve(Instrs.size());
232 for (auto *I : Instrs)
233 Nodes.push_back(DAG.getNode(I));
234 auto BndlPtr = std::make_unique<SchedBundle>(std::move(Nodes));
235 auto *Bndl = BndlPtr.get();
236 Bndls[Bndl] = std::move(BndlPtr);
237 return Bndl;
238}
239
240void Scheduler::eraseBundle(SchedBundle *SB) { Bndls.erase(SB); }
241
242bool Scheduler::tryScheduleUntil(ArrayRef<Instruction *> Instrs) {
243 // Create a bundle for Instrs. If it turns out the schedule is infeasible we
244 // will dismantle it.
245 auto *InstrsSB = createBundle(Instrs);
246 // Keep scheduling ready nodes until we either run out of ready nodes (i.e.,
247 // ReadyList is empty), or all nodes that correspond to `Instrs` (the nodes of
248 // which are collected in DeferredNodes) are all ready to schedule.
250 bool KeepScheduling = true;
251 while (KeepScheduling) {
252 enum class TryScheduleRes {
253 Success, ///> We successfully scheduled the bundle.
254 Failure, ///> We failed to schedule the bundle.
255 Finished, ///> We successfully scheduled the bundle and it is the last
256 /// bundle to be scheduled.
257 };
258 /// TryScheduleNode() attempts to schedule all DAG nodes in the bundle that
259 /// ReadyN is in. If it's not in a bundle it will create a singleton bundle
260 /// and will try to schedule it.
261 auto TryScheduleBndl = [this, InstrsSB](DGNode *ReadyN) -> TryScheduleRes {
262 auto *SB = ReadyN->getSchedBundle();
263 if (SB == nullptr) {
264 // If ReadyN does not belong to a bundle, create a singleton bundle
265 // and schedule it.
266 auto *SingletonSB = createBundle({ReadyN->getInstruction()});
267 scheduleAndUpdateReadyList(*SingletonSB);
268 return TryScheduleRes::Success;
269 }
270 if (SB->ready(Dir)) {
271 // Remove the rest of the bundle from the ready list.
272 // TODO: Perhaps change the Scheduler + ReadyList to operate on
273 // SchedBundles instead of DGNodes.
274 for (auto *N : *SB) {
275 if (N != ReadyN)
276 ReadyList.remove(N);
277 }
278 // If all nodes in the bundle are ready.
279 scheduleAndUpdateReadyList(*SB);
280 if (SB == InstrsSB)
281 // We just scheduled InstrsSB bundle, so we are done scheduling.
282 return TryScheduleRes::Finished;
283 return TryScheduleRes::Success;
284 }
285 return TryScheduleRes::Failure;
286 };
287 while (!ReadyList.empty()) {
288 auto *ReadyN = ReadyList.pop();
289 auto Res = TryScheduleBndl(ReadyN);
290 switch (Res) {
291 case TryScheduleRes::Success:
292 // We successfully scheduled ReadyN's bundle, keep scheduling.
293 continue;
294 case TryScheduleRes::Failure:
295 // We failed to schedule ReadyN's bundle, defer it to later and keep
296 // scheduling other ready instructions.
297 Retry.push_back(ReadyN);
298 continue;
299 case TryScheduleRes::Finished:
300 // We successfully scheduled the instruction bundle, so we are done.
301 return true;
302 }
303 llvm_unreachable("Unhandled TrySchedule() result");
304 }
305 // Try to schedule nodes from the Retry list.
306 KeepScheduling = false;
307 for (auto *N : make_early_inc_range(Retry)) {
308 auto Res = TryScheduleBndl(N);
309 if (Res == TryScheduleRes::Success) {
310 Retry.erase(find(Retry, N));
311 KeepScheduling = true;
312 }
313 }
314 }
315
316 // The Retry vector contains the ready nodes that were removed from the ready
317 // list but we could not schedule them (along with their parent bundle).
318 // Insert them back in.
319 for (auto *RetryN : Retry)
320 ReadyList.insert(RetryN);
321
322 eraseBundle(InstrsSB);
323 return false;
324}
325
326Scheduler::BndlSchedState
327Scheduler::getBndlSchedState(ArrayRef<Instruction *> Instrs) const {
328 assert(!Instrs.empty() && "Expected non-empty bundle");
329 auto *N0 = DAG.getNode(Instrs[0]);
330 auto *SB0 = N0 != nullptr ? N0->getSchedBundle() : nullptr;
331 bool AllUnscheduled = SB0 == nullptr;
332 bool FullyScheduled = SB0 != nullptr && !SB0->isSingleton();
333 for (auto *I : drop_begin(Instrs)) {
334 auto *N = DAG.getNode(I);
335 auto *SB = N != nullptr ? N->getSchedBundle() : nullptr;
336 if (SB != nullptr) {
337 // We found a scheduled instr, so there is now way all are unscheduled.
338 AllUnscheduled = false;
339 if (SB->isSingleton()) {
340 // We found an instruction in a temporarily scheduled singleton. There
341 // is no way that all instructions are scheduled in the same bundle.
342 FullyScheduled = false;
343 }
344 }
345
346 if (SB != SB0) {
347 // Either one of SB, SB0 is null, or they are in different bundles, so
348 // Instrs are definitely not in the same vector bundle.
349 FullyScheduled = false;
350 // One of SB, SB0 are in a vector bundle and they differ.
351 if ((SB != nullptr && !SB->isSingleton()) ||
352 (SB0 != nullptr && !SB0->isSingleton()))
353 return BndlSchedState::AlreadyScheduled;
354 }
355 }
356 return AllUnscheduled ? BndlSchedState::NoneScheduled
357 : FullyScheduled ? BndlSchedState::FullyScheduled
358 : BndlSchedState::TemporarilyScheduled;
359}
360
361void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
362 // | Legend: N: DGNode
363 // N <- DAGInterval.top() | B: SchedBundle
364 // N | *: Contains instruction in Instrs
365 // B <- TopI (Top of schedule) +-------------------------------------------
366 // B
367 // B *
368 // B
369 // B * <- LowestI (Lowest in Instrs)
370 // B
371 // N
372 // N
373 // N <- DAGInterval.bottom()
374 //
375 // Note: this figure assumes bottom-up scheduling. In top-down we have the
376 // top-down mirror image.
378 ? &*ScheduleFrontierOpt.value()
379 : VecUtils::getHighest(Instrs);
380 Instruction *LowestI = Dir == SchedDirection::BottomUp
381 ? VecUtils::getLowest(Instrs)
382 : &*ScheduleFrontierOpt.value();
383 Interval<Instruction> ResetIntvl(TopI, LowestI);
384 // The DAG Nodes contain state like the number of UnscheduledSuccs and the
385 // Scheduled flag. We need to reset their state. We need to do this for all
386 // nodes in ResetIntvl. Also destroy the singleton schedule bundles from
387 // LowestI all the way to the top.
388 for (auto &I : ResetIntvl) {
389 auto *N = DAG.getNode(&I);
390 if (N == nullptr)
391 continue;
392 auto *SB = N->getSchedBundle();
393 if (SB->isSingleton())
394 eraseBundle(SB);
395 N->resetScheduleState();
396 }
397 // Nodes that depend on the nodes in ResetIntvl also need to have their
398 // UnscheduledSuccs/UnscheduledPreds adjusted.
399 for (Instruction &I : ResetIntvl) {
400 auto *N = DAG.getNode(&I);
401 if (Dir == SchedDirection::BottomUp) {
402 // Recompute UnscheduledSuccs for nodes not only in ResetIntvl but even
403 // for nodes above the top of schedule.
404 for (auto *PredN : N->preds(DAG))
405 PredN->incrUnscheduledDeps();
406 } else {
408 // Recompute UnscheduledPreds for nodes not only in ResetIntvl but even
409 // for nodes below the bottom of schedule.
410 for (auto *SuccN : N->succs(DAG))
411 SuccN->incrUnscheduledDeps();
412 }
413 }
414
415 // Refill the ready list by visiting all the nodes in the unscheduled part of
416 // the DAG. In bottom-up that is from the top of the DAG down to LowestI; in
417 // top-down it is the mirror image, from TopI down to the bottom of the DAG.
418 ReadyList.clear();
419 Interval<Instruction> RefillIntvl =
421 ? Interval<Instruction>(DAG.getInterval().top(), LowestI)
422 : Interval<Instruction>(TopI, DAG.getInterval().bottom());
423 for (Instruction &I : RefillIntvl) {
424 auto *N = DAG.getNode(&I);
425 if (N->ready())
426 ReadyList.insert(N);
427 }
428}
429
430#ifndef NDEBUG
431void Scheduler::assertSameDirection(ArrayRef<Instruction *> Instrs) const {
432 // Check that we are not switching scheduling direction.
433 switch (Dir) {
435 assert(none_of(Instrs,
436 [this](Instruction *I) {
437 return ScheduleFrontierOpt->comesBefore(*I);
438 }) &&
439 "Wrong scheduling direction!");
440 break;
442 assert(all_of(Instrs,
443 [this](Instruction *I) {
444 return ScheduleFrontierOpt->comesBefore(*I);
445 }) &&
446 "Wrong scheduling direction!");
447 break;
448 }
449}
450#endif // NDEBUG
451
453 assert(all_of(drop_begin(Instrs),
454 [Instrs](Instruction *I) {
455 return I->getParent() == (*Instrs.begin())->getParent();
456 }) &&
457 "Instrs not in the same BB, should have been rejected by Legality!");
458 // TODO: For now don't cross BBs.
459 if (!DAG.getInterval().empty()) {
460 auto *BB = DAG.getInterval().top()->getParent();
461 if (any_of(Instrs, [BB](auto *I) { return I->getParent() != BB; }))
462 return false;
463 }
464 if (ScheduledBB == nullptr)
465 ScheduledBB = Instrs[0]->getParent();
466 // We don't support crossing BBs for now.
467 if (any_of(Instrs,
468 [this](Instruction *I) { return I->getParent() != ScheduledBB; }))
469 return false;
470
471 auto GetSchedPoint = [](SchedDirection Dir,
472 const auto &Instrs) -> SchedulingPoint {
473 switch (Dir) {
475 return SchedulingPoint(VecUtils::getLowest(Instrs)->getIterator())
476 .getNext();
478 return SchedulingPoint(VecUtils::getHighest(Instrs)->getIterator())
479 .getPrev();
480 }
481 llvm_unreachable("Unhandled Dir!");
482 };
483 auto SchedState = getBndlSchedState(Instrs);
484 switch (SchedState) {
485 case BndlSchedState::FullyScheduled:
486 // Nothing to do.
487 return true;
488 case BndlSchedState::AlreadyScheduled:
489 // Instructions are part of a different vector schedule, so we can't
490 // schedule \p Instrs in the same bundle (without destroying the existing
491 // schedule).
492 return false;
493 case BndlSchedState::TemporarilyScheduled:
494 // If one or more instrs are already scheduled we need to destroy the
495 // top-most part of the schedule that includes the instrs in the bundle and
496 // re-schedule.
497 DAG.extend(Instrs);
498 trimSchedule(Instrs);
499 ScheduleFrontierOpt = GetSchedPoint(Dir, Instrs);
500 return tryScheduleUntil(Instrs);
501 case BndlSchedState::NoneScheduled: {
502 // TODO: Set the window of the DAG that we are interested in.
503 if (!ScheduleFrontierOpt) {
504 // We start scheduling at the bottom instr of Instrs (top in TopDown).
505 ScheduleFrontierOpt = GetSchedPoint(Dir, Instrs);
506 } else {
507#ifndef NDEBUG
508 assertSameDirection(Instrs);
509#endif
510 }
511 // Extend the DAG to include Instrs.
512 Interval<Instruction> Extension = DAG.extend(Instrs);
513 // Add nodes from the new interval to ready list if they are ready.
514 for (auto &I : Extension) {
515 auto *N = DAG.getNode(&I);
516 if (N->scheduled())
517 continue;
518 if (N->ready() && !ReadyList.contains(N))
519 ReadyList.insert(N);
520 }
521 // Try schedule all nodes until we can schedule Instrs back-to-back.
522 return tryScheduleUntil(Instrs);
523 }
524 }
525 llvm_unreachable("Unhandled BndlSchedState enum");
526}
527
528#ifndef NDEBUG
530 OS << "ReadyList:\n";
531 ReadyList.dump(OS);
532 OS << "Dir=" << schedDirectionToStr(Dir) << " "
533 << (Dir == SchedDirection::BottomUp ? "Top" : "Bottom")
534 << " of schedule: ";
535 if (ScheduleFrontierOpt)
536 OS << **ScheduleFrontierOpt;
537 else
538 OS << "Empty";
539 OS << "\n";
540}
541void Scheduler::dump() const { dump(dbgs()); }
542#endif // NDEBUG
543
544} // namespace llvm::sandboxir
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition MD5.cpp:57
std::pair< uint64_t, uint64_t > Interval
iterator begin() const
Definition ArrayRef.h:129
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
void reserve(size_type N)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
An ArrayRef of Values or Instructions that we can print/dump for debugging.
Definition VecUtils.h:39
A DependencyGraph Node that points to an Instruction and contains memory dependency edges.
Instruction * getInstruction() const
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
LLVM_ABI BBIterator getIterator() const
\Returns a BasicBlock::iterator for this Instruction.
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
LLVM_DUMP_METHOD void dump() const
Definition Scheduler.cpp:63
The nodes that need to be scheduled back-to-back in a single scheduling cycle form a SchedBundle.
Definition Scheduler.h:128
LLVM_ABI DGNode * getBot() const
\Returns the bundle node that comes after the others in program order.
Definition Scheduler.cpp:24
LLVM_ABI DGNode * getTop() const
\Returns the bundle node that comes before the others in program order.
Definition Scheduler.cpp:15
SmallVector< DGNode *, 4 > ContainerTy
Definition Scheduler.h:130
LLVM_DUMP_METHOD void dump() const
Definition Scheduler.cpp:48
LLVM_ABI void cluster(BasicBlock::iterator Where)
Move all bundle instructions to Where back-to-back.
Definition Scheduler.cpp:33
LLVM_DUMP_METHOD void dump() const
LLVM_ABI bool trySchedule(BndlRef< Instruction * > Instrs)
Tries to build a schedule that includes all of Instrs scheduled at the same scheduling cycle.
The scheduling point in the context of the Scheduler points to the top-of-schedule (i....
Definition Scheduler.h:198
SchedulingPoint getNext() const
Returns the SchedulingPoint pointing after this.
Definition Scheduler.h:261
BasicBlock * atEndOrNull() const
If the SchedulingPoint points after the last instruction in the BB then this returns the correspondin...
Definition Scheduler.h:237
Instruction * atInstrOrNull() const
Returns the instruction pointed to by this SchedulingPoint or null if we are before/after BB.
Definition Scheduler.h:245
LLVM_DUMP_METHOD void dump() const
Definition Scheduler.cpp:77
SchedulingPoint getPrev() const
Returns the SchedulingPoint pointing before this.
Definition Scheduler.h:268
BasicBlock * atBeforeBeginOrNull() const
If the SchedulingPoint points to before the beginning of a BB, then this returns that BB,...
Definition Scheduler.h:230
void print(raw_ostream &OS) const
Definition Scheduler.cpp:68
Represents a Def-use/Use-def edge in SandboxIR.
Definition Use.h:43
A SandboxIR Value has users. This is the base class.
Definition Value.h:72
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:240
static Instruction * getHighest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is highest in the BB.
Definition VecUtils.h:250
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
StringLiteral schedDirectionToStr(SchedDirection Dir)
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
template class LLVM_TEMPLATE_ABI Interval< Instruction >
Definition Interval.cpp:46
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1781
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Success
The lock was released successfully.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
#define N