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
144        constant values for each operand of this operation or null if that
145        operand is not a constant.
146
147        This method may be called speculatively on operations where the provided
148        operands are not necessarily the same as the operation's current
149        operands. This may occur in analyses that wish to determine "what would
150        be the region invocations if these were the operands?"
151      }],
152      "void", "getRegionInvocationBounds",
153      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands,
154           "::llvm::SmallVectorImpl<::mlir::InvocationBounds> &"
155             :$invocationBounds), [{}],
156       [{ invocationBounds.append($_op->getNumRegions(),
157                                  ::mlir::InvocationBounds::getUnknown()); }]
158    >,
159  ];
160
161  let verify = [{
162    static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(),
163                  "expected operation to have non-zero regions");
164    return success();
165  }];
166
167  let extraClassDeclaration = [{
168    /// Convenience helper in case none of the operands is known.
169    void getSuccessorRegions(Optional<unsigned> index,
170                             SmallVectorImpl<RegionSuccessor> &regions) {
171       SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands());
172       getSuccessorRegions(index, nullAttrs, regions);
173    }
174
175    /// Verify types along control flow edges described by this interface.
176    static LogicalResult verifyTypes(Operation *op) {
177      return detail::verifyTypesAlongControlFlowEdges(op);
178    }
179  }];
180}
181
182//===----------------------------------------------------------------------===//
183// RegionBranchTerminatorOpInterface
184//===----------------------------------------------------------------------===//
185
186def RegionBranchTerminatorOpInterface :
187  OpInterface<"RegionBranchTerminatorOpInterface"> {
188  let description = [{
189    This interface provides information for branching terminator operations
190    in the presence of a parent RegionBranchOpInterface implementation. It
191    specifies which operands are passed to which successor region.
192  }];
193  let cppNamespace = "::mlir";
194
195  let methods = [
196    InterfaceMethod<[{
197        Returns a mutable range of operands that are semantically "returned" by
198        passing them to the region successor given by `index`.  If `index` is
199        None, this function returns the operands that are passed as a result to
200        the parent operation.
201      }],
202      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
203      (ins "::mlir::Optional<unsigned>":$index)
204    >,
205    InterfaceMethod<[{
206        Returns a range of operands that are semantically "returned" by passing
207        them to the region successor given by `index`.  If `index` is None, this
208        function returns the operands that are passed as a result to the parent
209        operation.
210      }],
211      "::mlir::OperandRange", "getSuccessorOperands",
212      (ins "::mlir::Optional<unsigned>":$index), [{}],
213      /*defaultImplementation=*/[{
214        return $_op.getMutableSuccessorOperands(index);
215      }]
216    >
217  ];
218
219  let verify = [{
220    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
221                  "expected operation to be a terminator");
222    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
223                  "expected operation to have zero results");
224    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
225                  "expected operation to have zero successors");
226    return success();
227  }];
228}
229
230//===----------------------------------------------------------------------===//
231// ControlFlow Traits
232//===----------------------------------------------------------------------===//
233
234// Op is "return-like".
235def ReturnLike : NativeOpTrait<"ReturnLike">;
236
237#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
238