MLIR 22.0.0git
ControlFlowInterfaces.cpp
Go to the documentation of this file.
1//===- ControlFlowInterfaces.cpp - ControlFlow Interfaces -----------------===//
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 <utility>
10
12#include "mlir/IR/Operation.h"
14#include "llvm/Support/DebugLog.h"
15
16using namespace mlir;
17
18//===----------------------------------------------------------------------===//
19// ControlFlowInterfaces
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
23
25 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
26}
27
28SuccessorOperands::SuccessorOperands(unsigned int producedOperandCount,
29 MutableOperandRange forwardedOperands)
30 : producedOperandCount(producedOperandCount),
31 forwardedOperands(std::move(forwardedOperands)) {}
32
33//===----------------------------------------------------------------------===//
34// BranchOpInterface
35//===----------------------------------------------------------------------===//
36
37/// Returns the `BlockArgument` corresponding to operand `operandIndex` in some
38/// successor if 'operandIndex' is within the range of 'operands', or
39/// std::nullopt if `operandIndex` isn't a successor operand index.
40std::optional<BlockArgument>
42 unsigned operandIndex, Block *successor) {
43 LDBG() << "Getting branch successor argument for operand index "
44 << operandIndex << " in successor block";
45
46 OperandRange forwardedOperands = operands.getForwardedOperands();
47 // Check that the operands are valid.
48 if (forwardedOperands.empty()) {
49 LDBG() << "No forwarded operands, returning nullopt";
50 return std::nullopt;
51 }
52
53 // Check to ensure that this operand is within the range.
54 unsigned operandsStart = forwardedOperands.getBeginOperandIndex();
55 if (operandIndex < operandsStart ||
56 operandIndex >= (operandsStart + forwardedOperands.size())) {
57 LDBG() << "Operand index " << operandIndex << " out of range ["
58 << operandsStart << ", "
59 << (operandsStart + forwardedOperands.size())
60 << "), returning nullopt";
61 return std::nullopt;
62 }
63
64 // Index the successor.
65 unsigned argIndex =
66 operands.getProducedOperandCount() + operandIndex - operandsStart;
67 LDBG() << "Computed argument index " << argIndex << " for successor block";
68 return successor->getArgument(argIndex);
69}
70
71/// Verify that the given operands match those of the given successor block.
72LogicalResult
74 const SuccessorOperands &operands) {
75 LDBG() << "Verifying branch successor operands for successor #" << succNo
76 << " in operation " << op->getName();
77
78 // Check the count.
79 unsigned operandCount = operands.size();
80 Block *destBB = op->getSuccessor(succNo);
81 LDBG() << "Branch has " << operandCount << " operands, target block has "
82 << destBB->getNumArguments() << " arguments";
83
84 if (operandCount != destBB->getNumArguments())
85 return op->emitError() << "branch has " << operandCount
86 << " operands for successor #" << succNo
87 << ", but target block has "
88 << destBB->getNumArguments();
89
90 // Check the types.
91 LDBG() << "Checking type compatibility for "
92 << (operandCount - operands.getProducedOperandCount())
93 << " forwarded operands";
94 for (unsigned i = operands.getProducedOperandCount(); i != operandCount;
95 ++i) {
96 Type operandType = operands[i].getType();
97 Type argType = destBB->getArgument(i).getType();
98 LDBG() << "Checking type compatibility: operand type " << operandType
99 << " vs argument type " << argType;
100
101 if (!cast<BranchOpInterface>(op).areTypesCompatible(operandType, argType))
102 return op->emitError() << "type mismatch for bb argument #" << i
103 << " of successor #" << succNo;
104 }
105
106 LDBG() << "Branch successor operand verification successful";
107 return success();
108}
109
110//===----------------------------------------------------------------------===//
111// WeightedBranchOpInterface
112//===----------------------------------------------------------------------===//
113
114static LogicalResult verifyWeights(Operation *op,
116 std::size_t expectedWeightsNum,
117 llvm::StringRef weightAnchorName,
118 llvm::StringRef weightRefName) {
119 if (weights.empty())
120 return success();
121
122 if (weights.size() != expectedWeightsNum)
123 return op->emitError() << "expects number of " << weightAnchorName
124 << " weights to match number of " << weightRefName
125 << ": " << weights.size() << " vs "
126 << expectedWeightsNum;
127
128 if (llvm::all_of(weights, [](int32_t value) { return value == 0; }))
129 return op->emitError() << "branch weights cannot all be zero";
130
131 return success();
132}
133
136 cast<WeightedBranchOpInterface>(op).getWeights();
137 return verifyWeights(op, weights, op->getNumSuccessors(), "branch",
138 "successors");
139}
140
141//===----------------------------------------------------------------------===//
142// WeightedRegionBranchOpInterface
143//===----------------------------------------------------------------------===//
144
147 cast<WeightedRegionBranchOpInterface>(op).getWeights();
148 return verifyWeights(op, weights, op->getNumRegions(), "region", "regions");
149}
150
151//===----------------------------------------------------------------------===//
152// RegionBranchOpInterface
153//===----------------------------------------------------------------------===//
154
155/// Verify that types match along control flow edges described the given op.
157 auto regionInterface = cast<RegionBranchOpInterface>(op);
158
159 // Verify all control flow edges from region branch points to region
160 // successors.
161 SmallVector<RegionBranchPoint> regionBranchPoints =
162 regionInterface.getAllRegionBranchPoints();
163 for (const RegionBranchPoint &branchPoint : regionBranchPoints) {
165 regionInterface.getSuccessorRegions(branchPoint, successors);
166 for (const RegionSuccessor &successor : successors) {
167 // Helper function that print the region branch point and the region
168 // successor.
169 auto emitRegionEdgeError = [&]() {
171 regionInterface->emitOpError("along control flow edge from ");
172 if (branchPoint.isParent()) {
173 diag << "parent";
174 diag.attachNote(op->getLoc()) << "region branch point";
175 } else {
176 diag << "Operation "
177 << branchPoint.getTerminatorPredecessorOrNull()->getName();
178 diag.attachNote(
179 branchPoint.getTerminatorPredecessorOrNull()->getLoc())
180 << "region branch point";
181 }
182 diag << " to ";
183 if (Region *region = successor.getSuccessor()) {
184 diag << "Region #" << region->getRegionNumber();
185 } else {
186 diag << "parent";
187 }
188 return diag;
189 };
190
191 // Verify number of successor operands and successor inputs.
192 OperandRange succOperands =
193 regionInterface.getSuccessorOperands(branchPoint, successor);
194 ValueRange succInputs = successor.getSuccessorInputs();
195 if (succOperands.size() != succInputs.size()) {
196 return emitRegionEdgeError()
197 << ": region branch point has " << succOperands.size()
198 << " operands, but region successor needs " << succInputs.size()
199 << " inputs";
200 }
201
202 // Verify that the types are compatible.
203 TypeRange succInputTypes = succInputs.getTypes();
204 TypeRange succOperandTypes = succOperands.getTypes();
205 for (const auto &typesIdx :
206 llvm::enumerate(llvm::zip(succOperandTypes, succInputTypes))) {
207 Type succOperandType = std::get<0>(typesIdx.value());
208 Type succInputType = std::get<1>(typesIdx.value());
209 if (!regionInterface.areTypesCompatible(succOperandType, succInputType))
210 return emitRegionEdgeError()
211 << ": successor operand type #" << typesIdx.index() << " "
212 << succOperandType << " should match successor input type #"
213 << typesIdx.index() << " " << succInputType;
214 }
215 }
216 }
217 return success();
218}
219
220/// Stop condition for `traverseRegionGraph`. The traversal is interrupted if
221/// this function returns "true" for a successor region. The first parameter is
222/// the successor region. The second parameter indicates all already visited
223/// regions.
225
226/// Traverse the region graph starting at `begin`. The traversal is interrupted
227/// if `stopCondition` evaluates to "true" for a successor region. In that case,
228/// this function returns "true". Otherwise, if the traversal was not
229/// interrupted, this function returns "false".
230static bool traverseRegionGraph(Region *begin,
231 StopConditionFn stopConditionFn) {
232 auto op = cast<RegionBranchOpInterface>(begin->getParentOp());
233 LDBG() << "Starting region graph traversal from region #"
234 << begin->getRegionNumber() << " in operation " << op->getName();
235
236 SmallVector<bool> visited(op->getNumRegions(), false);
237 visited[begin->getRegionNumber()] = true;
238 LDBG() << "Initialized visited array with " << op->getNumRegions()
239 << " regions";
240
241 // Retrieve all successors of the region and enqueue them in the worklist.
242 SmallVector<Region *> worklist;
243 auto enqueueAllSuccessors = [&](Region *region) {
244 LDBG() << "Enqueuing successors for region #" << region->getRegionNumber();
245 SmallVector<Attribute> operandAttributes(op->getNumOperands());
246 for (Block &block : *region) {
247 if (block.empty())
248 continue;
249 auto terminator =
250 dyn_cast<RegionBranchTerminatorOpInterface>(block.back());
251 if (!terminator)
252 continue;
254 operandAttributes.resize(terminator->getNumOperands());
255 terminator.getSuccessorRegions(operandAttributes, successors);
256 LDBG() << "Found " << successors.size()
257 << " successors from terminator in block";
258 for (RegionSuccessor successor : successors) {
259 if (!successor.isParent()) {
260 worklist.push_back(successor.getSuccessor());
261 LDBG() << "Added region #"
262 << successor.getSuccessor()->getRegionNumber()
263 << " to worklist";
264 } else {
265 LDBG() << "Skipping parent successor";
266 }
267 }
268 }
269 };
270 enqueueAllSuccessors(begin);
271 LDBG() << "Initial worklist size: " << worklist.size();
272
273 // Process all regions in the worklist via DFS.
274 while (!worklist.empty()) {
275 Region *nextRegion = worklist.pop_back_val();
276 LDBG() << "Processing region #" << nextRegion->getRegionNumber()
277 << " from worklist (remaining: " << worklist.size() << ")";
278
279 if (stopConditionFn(nextRegion, visited)) {
280 LDBG() << "Stop condition met for region #"
281 << nextRegion->getRegionNumber() << ", returning true";
282 return true;
283 }
284 if (!nextRegion->getParentOp()) {
285 llvm::errs() << "Region " << *nextRegion << " has no parent op\n";
286 return false;
287 }
288 if (visited[nextRegion->getRegionNumber()]) {
289 LDBG() << "Region #" << nextRegion->getRegionNumber()
290 << " already visited, skipping";
291 continue;
292 }
293 visited[nextRegion->getRegionNumber()] = true;
294 LDBG() << "Marking region #" << nextRegion->getRegionNumber()
295 << " as visited";
296 enqueueAllSuccessors(nextRegion);
297 }
298
299 LDBG() << "Traversal completed, returning false";
300 return false;
301}
302
303/// Return `true` if region `r` is reachable from region `begin` according to
304/// the RegionBranchOpInterface (by taking a branch).
305static bool isRegionReachable(Region *begin, Region *r) {
306 assert(begin->getParentOp() == r->getParentOp() &&
307 "expected that both regions belong to the same op");
308 return traverseRegionGraph(begin,
309 [&](Region *nextRegion, ArrayRef<bool> visited) {
310 // Interrupt traversal if `r` was reached.
311 return nextRegion == r;
312 });
313}
314
315/// Return `true` if `a` and `b` are in mutually exclusive regions.
316///
317/// 1. Find the first common of `a` and `b` (ancestor) that implements
318/// RegionBranchOpInterface.
319/// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are
320/// contained.
321/// 3. Check if `regionA` and `regionB` are mutually exclusive. They are
322/// mutually exclusive if they are not reachable from each other as per
323/// RegionBranchOpInterface::getSuccessorRegions.
325 LDBG() << "Checking if operations are in mutually exclusive regions: "
326 << a->getName() << " and " << b->getName();
327
328 assert(a && "expected non-empty operation");
329 assert(b && "expected non-empty operation");
330
331 auto branchOp = a->getParentOfType<RegionBranchOpInterface>();
332 while (branchOp) {
333 LDBG() << "Checking branch operation " << branchOp->getName();
334
335 // Check if b is inside branchOp. (We already know that a is.)
336 if (!branchOp->isProperAncestor(b)) {
337 LDBG() << "Operation b is not inside branchOp, checking next ancestor";
338 // Check next enclosing RegionBranchOpInterface.
339 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
340 continue;
341 }
342
343 LDBG() << "Both operations are inside branchOp, finding their regions";
344
345 // b is contained in branchOp. Retrieve the regions in which `a` and `b`
346 // are contained.
347 Region *regionA = nullptr, *regionB = nullptr;
348 for (Region &r : branchOp->getRegions()) {
349 if (r.findAncestorOpInRegion(*a)) {
350 assert(!regionA && "already found a region for a");
351 regionA = &r;
352 LDBG() << "Found region #" << r.getRegionNumber() << " for operation a";
353 }
354 if (r.findAncestorOpInRegion(*b)) {
355 assert(!regionB && "already found a region for b");
356 regionB = &r;
357 LDBG() << "Found region #" << r.getRegionNumber() << " for operation b";
358 }
359 }
360 assert(regionA && regionB && "could not find region of op");
361
362 LDBG() << "Region A: #" << regionA->getRegionNumber() << ", Region B: #"
363 << regionB->getRegionNumber();
364
365 // `a` and `b` are in mutually exclusive regions if both regions are
366 // distinct and neither region is reachable from the other region.
367 bool regionsAreDistinct = (regionA != regionB);
368 bool aNotReachableFromB = !isRegionReachable(regionA, regionB);
369 bool bNotReachableFromA = !isRegionReachable(regionB, regionA);
370
371 LDBG() << "Regions distinct: " << regionsAreDistinct
372 << ", A not reachable from B: " << aNotReachableFromB
373 << ", B not reachable from A: " << bNotReachableFromA;
374
375 bool mutuallyExclusive =
376 regionsAreDistinct && aNotReachableFromB && bNotReachableFromA;
377 LDBG() << "Operations are mutually exclusive: " << mutuallyExclusive;
378
379 return mutuallyExclusive;
380 }
381
382 // Could not find a common RegionBranchOpInterface among a's and b's
383 // ancestors.
384 LDBG() << "No common RegionBranchOpInterface found, operations are not "
385 "mutually exclusive";
386 return false;
387}
388
389bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) {
390 LDBG() << "Checking if region #" << index << " is repetitive in operation "
391 << getOperation()->getName();
392
393 Region *region = &getOperation()->getRegion(index);
394 bool isRepetitive = isRegionReachable(region, region);
395
396 LDBG() << "Region #" << index << " is repetitive: " << isRepetitive;
397 return isRepetitive;
398}
399
400bool RegionBranchOpInterface::hasLoop() {
401 LDBG() << "Checking if operation " << getOperation()->getName()
402 << " has loops";
403
404 SmallVector<RegionSuccessor> entryRegions;
405 getSuccessorRegions(RegionBranchPoint::parent(), entryRegions);
406 LDBG() << "Found " << entryRegions.size() << " entry regions";
407
408 for (RegionSuccessor successor : entryRegions) {
409 if (!successor.isParent()) {
410 LDBG() << "Checking entry region #"
411 << successor.getSuccessor()->getRegionNumber() << " for loops";
412
413 bool hasLoop =
414 traverseRegionGraph(successor.getSuccessor(),
415 [](Region *nextRegion, ArrayRef<bool> visited) {
416 // Interrupt traversal if the region was already
417 // visited.
418 return visited[nextRegion->getRegionNumber()];
419 });
420
421 if (hasLoop) {
422 LDBG() << "Found loop in entry region #"
423 << successor.getSuccessor()->getRegionNumber();
424 return true;
425 }
426 } else {
427 LDBG() << "Skipping parent successor";
428 }
429 }
430
431 LDBG() << "No loops found in operation";
432 return false;
433}
434
436RegionBranchOpInterface::getSuccessorOperands(RegionBranchPoint src,
437 RegionSuccessor dest) {
438 if (src.isParent())
439 return getEntrySuccessorOperands(dest);
440 auto terminator = cast<RegionBranchTerminatorOpInterface>(
442 return terminator.getSuccessorOperands(dest);
443}
444
446 return MutableArrayRef<OpOperand>(operands.getBase(), operands.size());
447}
448
449static void
450getSuccessorOperandInputMapping(RegionBranchOpInterface branchOp,
452 RegionBranchPoint src) {
454 branchOp.getSuccessorRegions(src, successors);
455 for (RegionSuccessor dst : successors) {
456 OperandRange operands = branchOp.getSuccessorOperands(src, dst);
457 assert(operands.size() == dst.getSuccessorInputs().size() &&
458 "expected the same number of operands and inputs");
459 for (const auto &[operand, input] : llvm::zip_equal(
460 operandsToOpOperands(operands), dst.getSuccessorInputs()))
461 mapping[&operand].push_back(input);
462 }
463}
464void RegionBranchOpInterface::getSuccessorOperandInputMapping(
466 std::optional<RegionBranchPoint> src) {
467 if (src.has_value()) {
468 ::getSuccessorOperandInputMapping(*this, mapping, src.value());
469 } else {
470 // No region branch point specified: populate the mapping for all possible
471 // region branch points.
472 for (RegionBranchPoint branchPoint : getAllRegionBranchPoints())
473 ::getSuccessorOperandInputMapping(*this, mapping, branchPoint);
474 }
475}
476
478RegionBranchOpInterface::getAllRegionBranchPoints() {
480 branchPoints.push_back(RegionBranchPoint::parent());
481 for (Region &region : getOperation()->getRegions()) {
482 for (Block &block : region) {
483 if (block.empty())
484 continue;
485 if (auto terminator =
486 dyn_cast<RegionBranchTerminatorOpInterface>(block.back()))
487 branchPoints.push_back(RegionBranchPoint(terminator));
488 }
489 }
490 return branchPoints;
491}
492
494 LDBG() << "Finding enclosing repetitive region for operation "
495 << op->getName();
496
497 while (Region *region = op->getParentRegion()) {
498 LDBG() << "Checking region #" << region->getRegionNumber()
499 << " in operation " << region->getParentOp()->getName();
500
501 op = region->getParentOp();
502 if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
503 LDBG()
504 << "Found RegionBranchOpInterface, checking if region is repetitive";
505 if (branchOp.isRepetitiveRegion(region->getRegionNumber())) {
506 LDBG() << "Found repetitive region #" << region->getRegionNumber();
507 return region;
508 }
509 } else {
510 LDBG() << "Parent operation does not implement RegionBranchOpInterface";
511 }
512 }
513
514 LDBG() << "No enclosing repetitive region found";
515 return nullptr;
516}
517
519 LDBG() << "Finding enclosing repetitive region for value";
520
521 Region *region = value.getParentRegion();
522 while (region) {
523 LDBG() << "Checking region #" << region->getRegionNumber()
524 << " in operation " << region->getParentOp()->getName();
525
526 Operation *op = region->getParentOp();
527 if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) {
528 LDBG()
529 << "Found RegionBranchOpInterface, checking if region is repetitive";
530 if (branchOp.isRepetitiveRegion(region->getRegionNumber())) {
531 LDBG() << "Found repetitive region #" << region->getRegionNumber();
532 return region;
533 }
534 } else {
535 LDBG() << "Parent operation does not implement RegionBranchOpInterface";
536 }
537 region = op->getParentRegion();
538 }
539
540 LDBG() << "No enclosing repetitive region found for value";
541 return nullptr;
542}
return success()
static LogicalResult verifyWeights(Operation *op, llvm::ArrayRef< int32_t > weights, std::size_t expectedWeightsNum, llvm::StringRef weightAnchorName, llvm::StringRef weightRefName)
static void getSuccessorOperandInputMapping(RegionBranchOpInterface branchOp, RegionBranchSuccessorMapping &mapping, RegionBranchPoint src)
static bool traverseRegionGraph(Region *begin, StopConditionFn stopConditionFn)
Traverse the region graph starting at begin.
function_ref< bool(Region *, ArrayRef< bool > visited)> StopConditionFn
Stop condition for traverseRegionGraph.
static bool isRegionReachable(Region *begin, Region *r)
Return true if region r is reachable from region begin according to the RegionBranchOpInterface (by t...
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static std::string diag(const llvm::Value &value)
static MutableArrayRef< OpOperand > operandsToOpOperands(OperandRange &operands)
Block represents an ordered list of Operations.
Definition Block.h:33
BlockArgument getArgument(unsigned i)
Definition Block.h:139
unsigned getNumArguments()
Definition Block.h:138
This class represents a diagnostic that is inflight and set to be reported.
This class provides a mutable adaptor for a range of operands.
Definition ValueRange.h:118
This class implements the operand iterators for the Operation class.
Definition ValueRange.h:43
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
type_range getTypes() const
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
unsigned getNumSuccessors()
Definition Operation.h:706
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition Operation.h:674
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:234
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:238
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:119
Block * getSuccessor(unsigned index)
Definition Operation.h:708
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition Operation.h:230
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
Operation * getTerminatorPredecessorOrNull() const
Returns the terminator if branching from a region.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
This class represents a successor of a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Definition Region.cpp:62
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:200
This class models how operands are forwarded to block arguments in control flow.
SuccessorOperands(MutableOperandRange forwardedOperands)
Constructs a SuccessorOperands with no produced operands that simply forwards operands to the success...
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
unsigned size() const
Returns the amount of operands passed to the successor.
OperandRange getForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
Region * getParentRegion()
Return the Region in which this Value is defined.
Definition Value.cpp:39
std::optional< BlockArgument > getBranchSuccessorArgument(const SuccessorOperands &operands, unsigned operandIndex, Block *successor)
Return the BlockArgument corresponding to operand operandIndex in some successor if operandIndex is w...
LogicalResult verifyRegionBranchWeights(Operation *op)
Verify that the region weights attached to an operation implementing WeightedRegiobBranchOpInterface ...
LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, const SuccessorOperands &operands)
Verify that the given operands match those of the given successor block.
LogicalResult verifyRegionBranchOpInterface(Operation *op)
Verify that types match along control flow edges described the given op.
LogicalResult verifyBranchWeights(Operation *op)
Verify that the branch weights attached to an operation implementing WeightedBranchOpInterface are co...
Include the generated interface declarations.
DenseMap< OpOperand *, SmallVector< Value > > RegionBranchSuccessorMapping
A mapping from successor operands to successor inputs.
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
Region * getEnclosingRepetitiveRegion(Operation *op)
Return the first enclosing region of the given op that may be executed repetitively as per RegionBran...
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152