13 #include "llvm/ADT/SmallPtrSet.h" 21 #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc" 24 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
29 : producedOperandCount(producedOperandCount),
30 forwardedOperands(std::move(forwardedOperands)) {}
41 unsigned operandIndex,
Block *successor) {
44 if (forwardedOperands.empty())
49 if (operandIndex < operandsStart ||
50 operandIndex >= (operandsStart + forwardedOperands.size()))
64 unsigned operandCount = operands.
size();
67 return op->
emitError() <<
"branch has " << operandCount
68 <<
" operands for successor #" << succNo
69 <<
", but target block has " 75 if (!cast<BranchOpInterface>(op).areTypesCompatible(
77 return op->
emitError() <<
"type mismatch for bb argument #" << i
78 <<
" of successor #" << succNo;
96 getInputsTypesForRegion) {
97 auto regionInterface = cast<RegionBranchOpInterface>(op);
100 regionInterface.getSuccessorRegions(sourceNo, successors);
104 if (!succ.isParent())
105 succRegionNo = succ.getSuccessor()->getRegionNumber();
110 diag <<
"Region #" << sourceNo.value();
112 diag <<
"parent operands";
116 diag <<
"Region #" << succRegionNo.value();
118 diag <<
"parent results";
123 if (!sourceTypes.has_value())
126 TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes();
127 if (sourceTypes->size() != succInputsTypes.size()) {
129 return printEdgeName(diag) <<
": source has " << sourceTypes->size()
130 <<
" operands, but target successor needs " 131 << succInputsTypes.size();
134 for (
const auto &typesIdx :
136 Type sourceType = std::get<0>(typesIdx.value());
137 Type inputType = std::get<1>(typesIdx.value());
138 if (!regionInterface.areTypesCompatible(sourceType, inputType)) {
140 return printEdgeName(diag)
141 <<
": source type #" << typesIdx.index() <<
" " << sourceType
142 <<
" should match input type #" << typesIdx.index() <<
" " 152 auto regionInterface = cast<RegionBranchOpInterface>(op);
155 return regionInterface.getSuccessorEntryOperands(regionNo).getTypes();
167 if (lhs.size() != rhs.size())
169 for (
auto types : llvm::zip(lhs, rhs)) {
170 if (!regionInterface.areTypesCompatible(std::get<0>(types),
171 std::get<1>(types))) {
179 for (
unsigned regionNo : llvm::seq(0U, op->
getNumRegions())) {
187 for (
Block &block : region) {
188 Operation *terminator = block.getTerminator();
189 auto terminatorOperands =
191 if (!terminatorOperands)
194 if (!regionReturnOperands) {
195 regionReturnOperands = terminatorOperands;
201 if (!areTypesCompatible(regionReturnOperands->getTypes(),
202 terminatorOperands->getTypes()))
205 <<
" operands mismatch between return-like terminators";
208 auto inputTypesFromRegion =
212 if (!regionReturnOperands)
216 return TypeRange(regionReturnOperands->getTypes());
230 "expected that both regions belong to the same op");
231 auto op = cast<RegionBranchOpInterface>(begin->
getParentOp());
237 auto enqueueAllSuccessors = [&](
unsigned index) {
239 op.getSuccessorRegions(index, successors);
241 if (!successor.isParent())
242 worklist.push_back(successor.getSuccessor()->getRegionNumber());
247 while (!worklist.empty()) {
248 unsigned nextRegion = worklist.pop_back_val();
251 if (visited[nextRegion])
253 visited[nextRegion] =
true;
254 enqueueAllSuccessors(nextRegion);
270 assert(a &&
"expected non-empty operation");
271 assert(b &&
"expected non-empty operation");
276 if (!branchOp->isProperAncestor(b)) {
278 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
284 Region *regionA =
nullptr, *regionB =
nullptr;
285 for (
Region &r : branchOp->getRegions()) {
286 if (r.findAncestorOpInRegion(*a)) {
287 assert(!regionA &&
"already found a region for a");
290 if (r.findAncestorOpInRegion(*b)) {
291 assert(!regionB &&
"already found a region for b");
295 assert(regionA && regionB &&
"could not find region of op");
308 bool RegionBranchOpInterface::isRepetitiveRegion(
unsigned index) {
309 Region *region = &getOperation()->getRegion(index);
313 void RegionBranchOpInterface::getSuccessorRegions(
315 unsigned numInputs = 0;
319 for (
Block &block : getOperation()->getRegion(*index)) {
320 Operation *terminator = block.getTerminator();
328 numInputs = getOperation()->getNumOperands();
331 getSuccessorRegions(index, operands, regions);
337 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
338 if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
348 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
363 return dyn_cast<RegionBranchTerminatorOpInterface>(operation) ||
380 if (
auto regionTerminatorInterface =
381 dyn_cast<RegionBranchTerminatorOpInterface>(operation))
382 return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex);
Include the generated interface declarations.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
static std::string diag(llvm::Value &v)
Optional< OperandRange > getRegionBranchSuccessorOperands(Operation *operation, Optional< unsigned > regionIndex)
Returns the read only operands that are passed to the region with the given regionIndex.
SuccessorOperands(MutableOperandRange forwardedOperands)
Constructs a SuccessorOperands with no produced operands that simply forwards operands to the success...
Operation is a basic unit of execution within MLIR.
unsigned getNumRegions()
Returns the number of regions held by this operation.
This class represents a diagnostic that is inflight and set to be reported.
Block represents an ordered list of Operations.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
unsigned getNumOperands()
bool isRegionReturnLike(Operation *operation)
Returns true if the given operation is either annotated with the ReturnLike trait or implements the R...
BlockArgument getArgument(unsigned i)
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
static constexpr const bool value
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
This class represents an efficient way to signal success or failure.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
unsigned size() const
Returns the amount of operands passed to the successor.
Block * getSuccessor(unsigned index)
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Region * getParentRegion()
Return the Region in which this Value is defined.
LogicalResult verifyTypesAlongControlFlowEdges(Operation *op)
Verify that types match along control flow edges described the given op.
unsigned getNumArguments()
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
static LogicalResult verifyTypesAlongAllEdges(Operation *op, Optional< unsigned > sourceNo, function_ref< Optional< TypeRange >(Optional< unsigned >)> getInputsTypesForRegion)
Verify that types match along all region control flow edges originating from sourceNo (region # if so...
Optional< MutableOperandRange > getMutableRegionBranchSuccessorOperands(Operation *operation, Optional< unsigned > regionIndex)
Returns the mutable operands that are passed to the region with the given regionIndex.
This class provides an abstraction over the various different ranges of value types.
This class provides a mutable adaptor for a range of operands.
This class models how operands are forwarded to block arguments in control flow.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Optional< BlockArgument > getBranchSuccessorArgument(const SuccessorOperands &operands, unsigned operandIndex, Block *successor)
Return the BlockArgument corresponding to operand operandIndex in some successor if operandIndex is w...
Operation * getParentOp()
Return the parent operation this region is attached to.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
OperandRange getForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
This class represents a successor of a region.
Type getType() const
Return the type of this value.
LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, const SuccessorOperands &operands)
Verify that the given operands match those of the given successor block.
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
Region * getEnclosingRepetitiveRegion(Operation *op)
Return the first enclosing region of the given op that may be executed repetitively as per RegionBran...
static bool isRegionReachable(Region *begin, Region *r)
Return true if region r is reachable from region begin according to the RegionBranchOpInterface (by t...
This class implements the operand iterators for the Operation class.
Region * getParentRegion()
Returns the region to which the instruction belongs.
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
This trait indicates that a terminator operation is "return-like".