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)) {}
39 std::optional<BlockArgument>
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;
92 diag <<
"Region #" << region->getRegionNumber();
94 diag <<
"parent operands";
98 diag <<
"Region #" << region->getRegionNumber();
100 diag <<
"parent results";
110 getInputsTypesForRegion) {
111 auto regionInterface = cast<RegionBranchOpInterface>(op);
114 regionInterface.getSuccessorRegions(sourcePoint, successors);
121 TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes();
122 if (sourceTypes->size() != succInputsTypes.size()) {
125 <<
": source has " << sourceTypes->size()
126 <<
" operands, but target successor needs "
127 << succInputsTypes.size();
130 for (
const auto &typesIdx :
132 Type sourceType = std::get<0>(typesIdx.value());
133 Type inputType = std::get<1>(typesIdx.value());
134 if (!regionInterface.areTypesCompatible(sourceType, inputType)) {
137 <<
": source type #" << typesIdx.index() <<
" " << sourceType
138 <<
" should match input type #" << typesIdx.index() <<
" "
148 auto regionInterface = cast<RegionBranchOpInterface>(op);
151 return regionInterface.getEntrySuccessorOperands(point).getTypes();
156 inputTypesFromParent)))
160 if (lhs.size() != rhs.size())
162 for (
auto types : llvm::zip(lhs, rhs)) {
163 if (!regionInterface.areTypesCompatible(std::get<0>(types),
164 std::get<1>(types))) {
179 for (
Block &block : region)
180 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(
181 block.getTerminator()))
182 regionReturnOps.push_back(terminator);
186 if (regionReturnOps.empty())
189 auto inputTypesForRegion =
191 std::optional<OperandRange> regionReturnOperands;
192 for (RegionBranchTerminatorOpInterface regionReturnOp : regionReturnOps) {
193 auto terminatorOperands = regionReturnOp.getSuccessorOperands(point);
195 if (!regionReturnOperands) {
196 regionReturnOperands = terminatorOperands;
202 if (!areTypesCompatible(regionReturnOperands->getTypes(),
203 terminatorOperands.getTypes())) {
206 <<
" operands mismatch between return-like terminators";
211 return TypeRange(regionReturnOperands->getTypes());
225 "expected that both regions belong to the same op");
226 auto op = cast<RegionBranchOpInterface>(begin->
getParentOp());
232 auto enqueueAllSuccessors = [&](
Region *region) {
234 op.getSuccessorRegions(region, successors);
236 if (!successor.isParent())
237 worklist.push_back(successor.getSuccessor());
239 enqueueAllSuccessors(begin);
242 while (!worklist.empty()) {
243 Region *nextRegion = worklist.pop_back_val();
249 enqueueAllSuccessors(nextRegion);
265 assert(a &&
"expected non-empty operation");
266 assert(b &&
"expected non-empty operation");
271 if (!branchOp->isProperAncestor(b)) {
273 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
279 Region *regionA =
nullptr, *regionB =
nullptr;
280 for (
Region &r : branchOp->getRegions()) {
281 if (r.findAncestorOpInRegion(*a)) {
282 assert(!regionA &&
"already found a region for a");
285 if (r.findAncestorOpInRegion(*b)) {
286 assert(!regionB &&
"already found a region for b");
290 assert(regionA && regionB &&
"could not find region of op");
304 Region *region = &getOperation()->getRegion(index);
311 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
322 if (
auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
static bool isRepetitiveRegion(Region *region, const BufferizationOptions &options)
static InFlightDiagnostic & printRegionEdgeName(InFlightDiagnostic &diag, RegionBranchPoint sourceNo, RegionBranchPoint succRegionNo)
static LogicalResult verifyTypesAlongAllEdges(Operation *op, RegionBranchPoint sourcePoint, function_ref< FailureOr< TypeRange >(RegionBranchPoint)> getInputsTypesForRegion)
Verify that types match along all region control flow edges originating from sourcePoint.
static bool isRegionReachable(Region *begin, Region *r)
Return true if region r is reachable from region begin according to the RegionBranchOpInterface (by t...
static std::string diag(const llvm::Value &value)
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
This class provides support for representing a failure result, or a valid value of type T.
This class represents a diagnostic that is inflight and set to be reported.
This class provides a mutable adaptor for a range of operands.
This class implements the operand iterators for the Operation class.
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
Operation is the basic unit of execution within MLIR.
Block * getSuccessor(unsigned index)
unsigned getNumRegions()
Returns the number of regions held by this operation.
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'.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Region * getParentRegion()
Returns the region to which the instruction belongs.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
Region * getRegionOrNull() const
Returns the region if branching from a region.
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.
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Operation * getParentOp()
Return the parent operation this region is attached to.
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.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Region * getParentRegion()
Return the Region in which this Value is defined.
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 verifyBranchSuccessorOperands(Operation *op, unsigned succNo, const SuccessorOperands &operands)
Verify that the given operands match those of the given successor block.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
LogicalResult verifyTypesAlongControlFlowEdges(Operation *op)
Verify that types match along control flow edges described the given op.
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
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...
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.