blob: bb635e77c4a127f49ceeaa6fab0a5a1f700f9c34 [file] [log] [blame]
//===-- 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> &regions) {
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