| //===-- ControlFlowInterfaces.td - ControlFlow Interfaces --*- tablegen -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains a set of interfaces that can be used to define information |
| // about control flow operations, e.g. branches. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_INTERFACES_CONTROLFLOWINTERFACES |
| #define MLIR_INTERFACES_CONTROLFLOWINTERFACES |
| |
| include "mlir/IR/OpBase.td" |
| |
| //===----------------------------------------------------------------------===// |
| // BranchOpInterface |
| //===----------------------------------------------------------------------===// |
| |
| def BranchOpInterface : OpInterface<"BranchOpInterface"> { |
| let description = [{ |
| This interface provides information for branching terminator operations, |
| i.e. terminator operations with successors. |
| }]; |
| let cppNamespace = "::mlir"; |
| |
| let methods = [ |
| InterfaceMethod<[{ |
| Returns a mutable range of operands that correspond to the arguments of |
| successor at the given index. Returns None if the operands to the |
| successor are non-materialized values, i.e. they are internal to the |
| operation. |
| }], |
| "::mlir::Optional<::mlir::MutableOperandRange>", "getMutableSuccessorOperands", |
| (ins "unsigned":$index) |
| >, |
| InterfaceMethod<[{ |
| Returns a range of operands that correspond to the arguments of |
| successor at the given index. Returns None if the operands to the |
| successor are non-materialized values, i.e. they are internal to the |
| operation. |
| }], |
| "::mlir::Optional<::mlir::OperandRange>", "getSuccessorOperands", |
| (ins "unsigned":$index), [{}], [{ |
| auto operands = $_op.getMutableSuccessorOperands(index); |
| return operands ? ::mlir::Optional<::mlir::OperandRange>(*operands) : ::llvm::None; |
| }] |
| >, |
| InterfaceMethod<[{ |
| Returns the `BlockArgument` corresponding to operand `operandIndex` in |
| some successor, or None if `operandIndex` isn't a successor operand |
| index. |
| }], |
| "::mlir::Optional<::mlir::BlockArgument>", "getSuccessorBlockArgument", |
| (ins "unsigned":$operandIndex), [{ |
| ::mlir::Operation *opaqueOp = $_op; |
| for (unsigned i = 0, e = opaqueOp->getNumSuccessors(); i != e; ++i) { |
| if (::mlir::Optional<::mlir::BlockArgument> arg = ::mlir::detail::getBranchSuccessorArgument( |
| $_op.getSuccessorOperands(i), operandIndex, |
| opaqueOp->getSuccessor(i))) |
| return arg; |
| } |
| return ::llvm::None; |
| }] |
| >, |
| InterfaceMethod<[{ |
| Returns the successor that would be chosen with the given constant |
| operands. Returns nullptr if a single successor could not be chosen. |
| }], |
| "::mlir::Block *", "getSuccessorForOperands", |
| (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands), [{}], |
| /*defaultImplementation=*/[{ return nullptr; }] |
| > |
| ]; |
| |
| let verify = [{ |
| auto concreteOp = ::mlir::cast<ConcreteOp>($_op); |
| for (unsigned i = 0, e = $_op->getNumSuccessors(); i != e; ++i) { |
| ::mlir::Optional<OperandRange> operands = concreteOp.getSuccessorOperands(i); |
| if (::mlir::failed(::mlir::detail::verifyBranchSuccessorOperands($_op, i, operands))) |
| return ::mlir::failure(); |
| } |
| return ::mlir::success(); |
| }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // RegionBranchOpInterface |
| //===----------------------------------------------------------------------===// |
| |
| def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> { |
| let description = [{ |
| This interface provides information for region operations that contain |
| branching behavior between held regions, i.e. this interface allows for |
| expressing control flow information for region holding operations. |
| }]; |
| let cppNamespace = "::mlir"; |
| |
| let methods = [ |
| InterfaceMethod<[{ |
| Returns the operands of this operation used as the entry arguments when |
| entering the region at `index`, which was specified as a successor of this |
| operation by `getSuccessorRegions`. These operands should correspond 1-1 |
| with the successor inputs specified in `getSuccessorRegions`. |
| }], |
| "::mlir::OperandRange", "getSuccessorEntryOperands", |
| (ins "unsigned":$index), [{}], /*defaultImplementation=*/[{ |
| auto operandEnd = this->getOperation()->operand_end(); |
| return ::mlir::OperandRange(operandEnd, operandEnd); |
| }] |
| >, |
| InterfaceMethod<[{ |
| Returns the viable successors of a region at `index`, or the possible |
| successors when branching from the parent op if `index` is None. These |
| are the regions that may be selected during the flow of control. If |
| `index` is None, `operands` is a set of optional attributes that |
| either correspond to a constant value for each operand of this |
| operation, or null if that operand is not a constant. If `index` is |
| valid, `operands` corresponds to the entry values of the region at |
| `index`. Only a region, i.e. a valid `index`, may use the parent |
| operation as a successor. This method allows for describing which |
| regions may be executed when entering an operation, and which regions |
| are executed after having executed another region of the parent op. The |
| successor region must be non-empty. |
| }], |
| "void", "getSuccessorRegions", |
| (ins "::mlir::Optional<unsigned>":$index, "::mlir::ArrayRef<::mlir::Attribute>":$operands, |
| "::mlir::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions) |
| >, |
| InterfaceMethod<[{ |
| Populates countPerRegion with the number of times this operation will |
| invoke the attached regions (assuming the regions yield normally, i.e. |
| do not abort or invoke an infinite loop). If the number of region |
| invocations is not known statically it will set the number of |
| invocations to `kUnknownNumRegionInvocations`. |
| |
| `operands` is a set of optional attributes that either correspond to a |
| constant values for each operand of this operation, or null if that |
| operand is not a constant. |
| }], |
| "void", "getNumRegionInvocations", |
| (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands, |
| "::mlir::SmallVectorImpl<int64_t> &":$countPerRegion), [{}], |
| /*defaultImplementation=*/[{ |
| unsigned numRegions = this->getOperation()->getNumRegions(); |
| assert(countPerRegion.empty()); |
| countPerRegion.resize(numRegions, kUnknownNumRegionInvocations); |
| }] |
| > |
| ]; |
| |
| let verify = [{ |
| static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(), |
| "expected operation to have non-zero regions"); |
| return success(); |
| }]; |
| |
| let extraClassDeclaration = [{ |
| /// Convenience helper in case none of the operands is known. |
| void getSuccessorRegions(Optional<unsigned> index, |
| SmallVectorImpl<RegionSuccessor> ®ions) { |
| SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands()); |
| getSuccessorRegions(index, nullAttrs, regions); |
| } |
| |
| /// Verify types along control flow edges described by this interface. |
| static LogicalResult verifyTypes(Operation *op) { |
| return detail::verifyTypesAlongControlFlowEdges(op); |
| } |
| }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // RegionBranchTerminatorOpInterface |
| //===----------------------------------------------------------------------===// |
| |
| def RegionBranchTerminatorOpInterface : |
| OpInterface<"RegionBranchTerminatorOpInterface"> { |
| let description = [{ |
| This interface provides information for branching terminator operations |
| in the presence of a parent RegionBranchOpInterface implementation. It |
| specifies which operands are passed to which successor region. |
| }]; |
| let cppNamespace = "::mlir"; |
| |
| let methods = [ |
| InterfaceMethod<[{ |
| Returns a mutable range of operands that are semantically "returned" by |
| passing them to the region successor given by `index`. If `index` is |
| None, this function returns the operands that are passed as a result to |
| the parent operation. |
| }], |
| "::mlir::MutableOperandRange", "getMutableSuccessorOperands", |
| (ins "::mlir::Optional<unsigned>":$index) |
| >, |
| InterfaceMethod<[{ |
| Returns a range of operands that are semantically "returned" by passing |
| them to the region successor given by `index`. If `index` is None, this |
| function returns the operands that are passed as a result to the parent |
| operation. |
| }], |
| "::mlir::OperandRange", "getSuccessorOperands", |
| (ins "::mlir::Optional<unsigned>":$index), [{}], |
| /*defaultImplementation=*/[{ |
| return $_op.getMutableSuccessorOperands(index); |
| }] |
| > |
| ]; |
| |
| let verify = [{ |
| static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(), |
| "expected operation to be a terminator"); |
| static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(), |
| "expected operation to have zero results"); |
| static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(), |
| "expected operation to have zero successors"); |
| return success(); |
| }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ControlFlow Traits |
| //===----------------------------------------------------------------------===// |
| |
| // Op is "return-like". |
| def ReturnLike : NativeOpTrait<"ReturnLike">; |
| |
| #endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES |