1//===-- ControlFlowInterfaces.td - ControlFlow Interfaces --*- tablegen -*-===//
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// This file contains a set of interfaces that can be used to define information
10// about control flow operations, e.g. branches.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_INTERFACES_CONTROLFLOWINTERFACES
15#define MLIR_INTERFACES_CONTROLFLOWINTERFACES
16
17include "mlir/IR/OpBase.td"
18
19//===----------------------------------------------------------------------===//
20// BranchOpInterface
21//===----------------------------------------------------------------------===//
22
23def BranchOpInterface : OpInterface<"BranchOpInterface"> {
24  let description = [{
25    This interface provides information for branching terminator operations,
26    i.e. terminator operations with successors.
27  }];
28  let cppNamespace = "::mlir";
29
30  let methods = [
31    InterfaceMethod<[{
32        Returns a mutable range of operands that correspond to the arguments of
33        successor at the given index. Returns None if the operands to the
34        successor are non-materialized values, i.e. they are internal to the
35        operation.
36      }],
37      "::mlir::Optional<::mlir::MutableOperandRange>", "getMutableSuccessorOperands",
38      (ins "unsigned":$index)
39    >,
40    InterfaceMethod<[{
41        Returns a range of operands that correspond to the arguments of
42        successor at the given index. Returns None if the operands to the
43        successor are non-materialized values, i.e. they are internal to the
44        operation.
45      }],
46      "::mlir::Optional<::mlir::OperandRange>", "getSuccessorOperands",
47      (ins "unsigned":$index), [{}], [{
48        auto operands = $_op.getMutableSuccessorOperands(index);
49        return operands ? ::mlir::Optional<::mlir::OperandRange>(*operands) : ::llvm::None;
50      }]
51    >,
52    InterfaceMethod<[{
53        Returns the `BlockArgument` corresponding to operand `operandIndex` in
54        some successor, or None if `operandIndex` isn't a successor operand
55        index.
56      }],
57      "::mlir::Optional<::mlir::BlockArgument>", "getSuccessorBlockArgument",
58      (ins "unsigned":$operandIndex), [{
59        ::mlir::Operation *opaqueOp = $_op;
60        for (unsigned i = 0, e = opaqueOp->getNumSuccessors(); i != e; ++i) {
61          if (::mlir::Optional<::mlir::BlockArgument> arg = ::mlir::detail::getBranchSuccessorArgument(
62                $_op.getSuccessorOperands(i), operandIndex,
63                opaqueOp->getSuccessor(i)))
64            return arg;
65        }
66        return ::llvm::None;
67      }]
68    >,
69    InterfaceMethod<[{
70        Returns the successor that would be chosen with the given constant
71        operands. Returns nullptr if a single successor could not be chosen.
72      }],
73      "::mlir::Block *", "getSuccessorForOperands",
74      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands), [{}],
75      /*defaultImplementation=*/[{ return nullptr; }]
76    >
77  ];
78
79  let verify = [{
80    auto concreteOp = ::mlir::cast<ConcreteOp>($_op);
81    for (unsigned i = 0, e = $_op->getNumSuccessors(); i != e; ++i) {
82      ::mlir::Optional<OperandRange> operands = concreteOp.getSuccessorOperands(i);
83      if (::mlir::failed(::mlir::detail::verifyBranchSuccessorOperands($_op, i, operands)))
84        return ::mlir::failure();
85    }
86    return ::mlir::success();
87  }];
88}
89
90//===----------------------------------------------------------------------===//
91// RegionBranchOpInterface
92//===----------------------------------------------------------------------===//
93
94def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
95  let description = [{
96    This interface provides information for region operations that contain
97    branching behavior between held regions, i.e. this interface allows for
98    expressing control flow information for region holding operations.
99  }];
100  let cppNamespace = "::mlir";
101
102  let methods = [
103    InterfaceMethod<[{
104        Returns the operands of this operation used as the entry arguments when
105        entering the region at `index`, which was specified as a successor of
106        this operation by `getSuccessorRegions`. These operands should
107        correspond 1-1 with the successor inputs specified in
108        `getSuccessorRegions`.
109      }],
110      "::mlir::OperandRange", "getSuccessorEntryOperands",
111      (ins "unsigned":$index), [{}], /*defaultImplementation=*/[{
112        auto operandEnd = this->getOperation()->operand_end();
113        return ::mlir::OperandRange(operandEnd, operandEnd);
114      }]
115    >,
116    InterfaceMethod<[{
117        Returns the viable successors of a region at `index`, or the possible
118        successors when branching from the parent op if `index` is None. These
119        are the regions that may be selected during the flow of control. If
120        `index` is None, `operands` is a set of optional attributes that
121        either correspond to a constant value for each operand of this
122        operation, or null if that operand is not a constant. If `index` is
123        valid, `operands` corresponds to the entry values of the region at
124        `index`. Only a region, i.e. a valid `index`, may use the parent
125        operation as a successor. This method allows for describing which
126        regions may be executed when entering an operation, and which regions
127        are executed after having executed another region of the parent op. The
128        successor region must be non-empty.
129      }],
130      "void", "getSuccessorRegions",
131      (ins "::mlir::Optional<unsigned>":$index,
132           "::mlir::ArrayRef<::mlir::Attribute>":$operands,
133           "::mlir::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions)
134    >,
135    InterfaceMethod<[{
136        Populates `invocationBounds` with the minimum and maximum number of
137        times this operation will invoke the attached regions (assuming the
138        regions yield normally, i.e. do not abort or invoke an infinite loop).
139        The minimum number of invocations is at least 0. If the maximum number
140        of invocations cannot be statically determined, then it will not have a
141        value (i.e., it is set to `llvm::None`).
142
143        `operands` is a set of optional attributes that either correspond to a
144        constant values for each operand of this operation, or null if that
145        operand is not a constant.
146      }],
147      "void", "getRegionInvocationBounds",
148      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands,
149           "::llvm::SmallVectorImpl<::mlir::InvocationBounds> &"
150             :$invocationBounds), [{}],
151       [{ invocationBounds.append($_op->getNumRegions(),
152                                  ::mlir::InvocationBounds::getUnknown()); }]
153    >,
154  ];
155
156  let verify = [{
157    static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(),
158                  "expected operation to have non-zero regions");
159    return success();
160  }];
161
162  let extraClassDeclaration = [{
163    /// Convenience helper in case none of the operands is known.
164    void getSuccessorRegions(Optional<unsigned> index,
165                             SmallVectorImpl<RegionSuccessor> &regions) {
166       SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands());
167       getSuccessorRegions(index, nullAttrs, regions);
168    }
169
170    /// Verify types along control flow edges described by this interface.
171    static LogicalResult verifyTypes(Operation *op) {
172      return detail::verifyTypesAlongControlFlowEdges(op);
173    }
174  }];
175}
176
177//===----------------------------------------------------------------------===//
178// RegionBranchTerminatorOpInterface
179//===----------------------------------------------------------------------===//
180
181def RegionBranchTerminatorOpInterface :
182  OpInterface<"RegionBranchTerminatorOpInterface"> {
183  let description = [{
184    This interface provides information for branching terminator operations
185    in the presence of a parent RegionBranchOpInterface implementation. It
186    specifies which operands are passed to which successor region.
187  }];
188  let cppNamespace = "::mlir";
189
190  let methods = [
191    InterfaceMethod<[{
192        Returns a mutable range of operands that are semantically "returned" by
193        passing them to the region successor given by `index`.  If `index` is
194        None, this function returns the operands that are passed as a result to
195        the parent operation.
196      }],
197      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
198      (ins "::mlir::Optional<unsigned>":$index)
199    >,
200    InterfaceMethod<[{
201        Returns a range of operands that are semantically "returned" by passing
202        them to the region successor given by `index`.  If `index` is None, this
203        function returns the operands that are passed as a result to the parent
204        operation.
205      }],
206      "::mlir::OperandRange", "getSuccessorOperands",
207      (ins "::mlir::Optional<unsigned>":$index), [{}],
208      /*defaultImplementation=*/[{
209        return $_op.getMutableSuccessorOperands(index);
210      }]
211    >
212  ];
213
214  let verify = [{
215    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
216                  "expected operation to be a terminator");
217    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
218                  "expected operation to have zero results");
219    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
220                  "expected operation to have zero successors");
221    return success();
222  }];
223}
224
225//===----------------------------------------------------------------------===//
226// ControlFlow Traits
227//===----------------------------------------------------------------------===//
228
229// Op is "return-like".
230def ReturnLike : NativeOpTrait<"ReturnLike">;
231
232#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
233