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    This interface is meant to model well-defined cases of control-flow of
29    value propagation, where what occurs along control-flow edges is assumed to
30    be side-effect free. For example, corresponding successor operands and
31    successor block arguments may have different types. In such cases,
32    `areTypesCompatible` can be implemented to compare types along control-flow
33    edges. By default, type equality is used.
34  }];
35  let cppNamespace = "::mlir";
36
37  let methods = [
38    InterfaceMethod<[{
39        Returns a mutable range of operands that correspond to the arguments of
40        successor at the given index. Returns None if the operands to the
41        successor are non-materialized values, i.e. they are internal to the
42        operation.
43      }],
44      "::mlir::Optional<::mlir::MutableOperandRange>", "getMutableSuccessorOperands",
45      (ins "unsigned":$index)
46    >,
47    InterfaceMethod<[{
48        Returns a range of operands that correspond to the arguments of
49        successor at the given index. Returns None if the operands to the
50        successor are non-materialized values, i.e. they are internal to the
51        operation.
52      }],
53      "::mlir::Optional<::mlir::OperandRange>", "getSuccessorOperands",
54      (ins "unsigned":$index), [{}], [{
55        auto operands = $_op.getMutableSuccessorOperands(index);
56        return operands ? ::mlir::Optional<::mlir::OperandRange>(*operands) : ::llvm::None;
57      }]
58    >,
59    InterfaceMethod<[{
60        Returns the `BlockArgument` corresponding to operand `operandIndex` in
61        some successor, or None if `operandIndex` isn't a successor operand
62        index.
63      }],
64      "::mlir::Optional<::mlir::BlockArgument>", "getSuccessorBlockArgument",
65      (ins "unsigned":$operandIndex), [{
66        ::mlir::Operation *opaqueOp = $_op;
67        for (unsigned i = 0, e = opaqueOp->getNumSuccessors(); i != e; ++i) {
68          if (::mlir::Optional<::mlir::BlockArgument> arg = ::mlir::detail::getBranchSuccessorArgument(
69                $_op.getSuccessorOperands(i), operandIndex,
70                opaqueOp->getSuccessor(i)))
71            return arg;
72        }
73        return ::llvm::None;
74      }]
75    >,
76    InterfaceMethod<[{
77        Returns the successor that would be chosen with the given constant
78        operands. Returns nullptr if a single successor could not be chosen.
79      }],
80      "::mlir::Block *", "getSuccessorForOperands",
81      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands), [{}],
82      /*defaultImplementation=*/[{ return nullptr; }]
83    >,
84    InterfaceMethod<[{
85        This method is called to compare types along control-flow edges. By
86        default, the types are checked as equal.
87      }],
88      "bool", "areTypesCompatible",
89      (ins "::mlir::Type":$lhs, "::mlir::Type":$rhs), [{}],
90       [{ return lhs == rhs; }]
91    >,
92  ];
93
94  let verify = [{
95    auto concreteOp = ::mlir::cast<ConcreteOp>($_op);
96    for (unsigned i = 0, e = $_op->getNumSuccessors(); i != e; ++i) {
97      ::mlir::Optional<OperandRange> operands = concreteOp.getSuccessorOperands(i);
98      if (::mlir::failed(::mlir::detail::verifyBranchSuccessorOperands($_op, i, operands)))
99        return ::mlir::failure();
100    }
101    return ::mlir::success();
102  }];
103}
104
105//===----------------------------------------------------------------------===//
106// RegionBranchOpInterface
107//===----------------------------------------------------------------------===//
108
109def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
110  let description = [{
111    This interface provides information for region operations that contain
112    branching behavior between held regions, i.e. this interface allows for
113    expressing control flow information for region holding operations.
114
115    This interface is meant to model well-defined cases of control-flow of
116    value propagation, where what occurs along control-flow edges is assumed to
117    be side-effect free. For example, corresponding successor operands and
118    successor block arguments may have different types. In such cases,
119    `areTypesCompatible` can be implemented to compare types along control-flow
120    edges. By default, type equality is used.
121  }];
122  let cppNamespace = "::mlir";
123
124  let methods = [
125    InterfaceMethod<[{
126        Returns the operands of this operation used as the entry arguments when
127        entering the region at `index`, which was specified as a successor of
128        this operation by `getSuccessorRegions`. These operands should
129        correspond 1-1 with the successor inputs specified in
130        `getSuccessorRegions`.
131      }],
132      "::mlir::OperandRange", "getSuccessorEntryOperands",
133      (ins "unsigned":$index), [{}], /*defaultImplementation=*/[{
134        auto operandEnd = this->getOperation()->operand_end();
135        return ::mlir::OperandRange(operandEnd, operandEnd);
136      }]
137    >,
138    InterfaceMethod<[{
139        Returns the viable successors of a region at `index`, or the possible
140        successors when branching from the parent op if `index` is None. These
141        are the regions that may be selected during the flow of control. If
142        `index` is None, `operands` is a set of optional attributes that
143        either correspond to a constant value for each operand of this
144        operation, or null if that operand is not a constant. If `index` is
145        valid, `operands` corresponds to the entry values of the region at
146        `index`. Only a region, i.e. a valid `index`, may use the parent
147        operation as a successor. This method allows for describing which
148        regions may be executed when entering an operation, and which regions
149        are executed after having executed another region of the parent op. The
150        successor region must be non-empty.
151      }],
152      "void", "getSuccessorRegions",
153      (ins "::mlir::Optional<unsigned>":$index,
154           "::mlir::ArrayRef<::mlir::Attribute>":$operands,
155           "::mlir::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions)
156    >,
157    InterfaceMethod<[{
158        Populates `invocationBounds` with the minimum and maximum number of
159        times this operation will invoke the attached regions (assuming the
160        regions yield normally, i.e. do not abort or invoke an infinite loop).
161        The minimum number of invocations is at least 0. If the maximum number
162        of invocations cannot be statically determined, then it will not have a
163        value (i.e., it is set to `llvm::None`).
164
165        `operands` is a set of optional attributes that either correspond to
166        constant values for each operand of this operation or null if that
167        operand is not a constant.
168
169        This method may be called speculatively on operations where the provided
170        operands are not necessarily the same as the operation's current
171        operands. This may occur in analyses that wish to determine "what would
172        be the region invocations if these were the operands?"
173      }],
174      "void", "getRegionInvocationBounds",
175      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands,
176           "::llvm::SmallVectorImpl<::mlir::InvocationBounds> &"
177             :$invocationBounds), [{}],
178       [{ invocationBounds.append($_op->getNumRegions(),
179                                  ::mlir::InvocationBounds::getUnknown()); }]
180    >,
181    InterfaceMethod<[{
182        This method is called to compare types along control-flow edges. By
183        default, the types are checked as equal.
184      }],
185      "bool", "areTypesCompatible",
186      (ins "::mlir::Type":$lhs, "::mlir::Type":$rhs), [{}],
187       [{ return lhs == rhs; }]
188    >,
189  ];
190
191  let verify = [{
192    static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(),
193                  "expected operation to have non-zero regions");
194    return detail::verifyTypesAlongControlFlowEdges($_op);
195  }];
196  let verifyWithRegions = 1;
197
198  let extraClassDeclaration = [{
199    /// Convenience helper in case none of the operands is known.
200    void getSuccessorRegions(Optional<unsigned> index,
201                             SmallVectorImpl<RegionSuccessor> &regions) {
202       SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands());
203       getSuccessorRegions(index, nullAttrs, regions);
204    }
205  }];
206}
207
208//===----------------------------------------------------------------------===//
209// RegionBranchTerminatorOpInterface
210//===----------------------------------------------------------------------===//
211
212def RegionBranchTerminatorOpInterface :
213  OpInterface<"RegionBranchTerminatorOpInterface"> {
214  let description = [{
215    This interface provides information for branching terminator operations
216    in the presence of a parent RegionBranchOpInterface implementation. It
217    specifies which operands are passed to which successor region.
218  }];
219  let cppNamespace = "::mlir";
220
221  let methods = [
222    InterfaceMethod<[{
223        Returns a mutable range of operands that are semantically "returned" by
224        passing them to the region successor given by `index`.  If `index` is
225        None, this function returns the operands that are passed as a result to
226        the parent operation.
227      }],
228      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
229      (ins "::mlir::Optional<unsigned>":$index)
230    >,
231    InterfaceMethod<[{
232        Returns a range of operands that are semantically "returned" by passing
233        them to the region successor given by `index`.  If `index` is None, this
234        function returns the operands that are passed as a result to the parent
235        operation.
236      }],
237      "::mlir::OperandRange", "getSuccessorOperands",
238      (ins "::mlir::Optional<unsigned>":$index), [{}],
239      /*defaultImplementation=*/[{
240        return $_op.getMutableSuccessorOperands(index);
241      }]
242    >
243  ];
244
245  let verify = [{
246    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
247                  "expected operation to be a terminator");
248    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
249                  "expected operation to have zero results");
250    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
251                  "expected operation to have zero successors");
252    return success();
253  }];
254}
255
256//===----------------------------------------------------------------------===//
257// ControlFlow Traits
258//===----------------------------------------------------------------------===//
259
260// Op is "return-like".
261def ReturnLike : NativeOpTrait<"ReturnLike">;
262
263#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
264