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 this
106        operation by `getSuccessorRegions`. These operands should correspond 1-1
107        with the successor inputs specified in `getSuccessorRegions`.
108      }],
109      "::mlir::OperandRange", "getSuccessorEntryOperands",
110      (ins "unsigned":$index), [{}], /*defaultImplementation=*/[{
111        auto operandEnd = this->getOperation()->operand_end();
112        return ::mlir::OperandRange(operandEnd, operandEnd);
113      }]
114    >,
115    InterfaceMethod<[{
116        Returns the viable successors of a region at `index`, or the possible
117        successors when branching from the parent op if `index` is None. These
118        are the regions that may be selected during the flow of control. If
119        `index` is None, `operands` is a set of optional attributes that
120        either correspond to a constant value for each operand of this
121        operation, or null if that operand is not a constant. If `index` is
122        valid, `operands` corresponds to the entry values of the region at
123        `index`. Only a region, i.e. a valid `index`, may use the parent
124        operation as a successor. This method allows for describing which
125        regions may be executed when entering an operation, and which regions
126        are executed after having executed another region of the parent op. The
127        successor region must be non-empty.
128      }],
129      "void", "getSuccessorRegions",
130      (ins "::mlir::Optional<unsigned>":$index, "::mlir::ArrayRef<::mlir::Attribute>":$operands,
131           "::mlir::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions)
132    >,
133    InterfaceMethod<[{
134        Populates countPerRegion with the number of times this operation will
135        invoke the attached regions (assuming the regions yield normally, i.e.
136        do not abort or invoke an infinite loop). If the number of region
137        invocations is not known statically it will set the number of
138        invocations to `kUnknownNumRegionInvocations`.
139
140        `operands` is a set of optional attributes that either correspond to a
141        constant values for each operand of this operation, or null if that
142        operand is not a constant.
143      }],
144      "void", "getNumRegionInvocations",
145      (ins "::mlir::ArrayRef<::mlir::Attribute>":$operands,
146           "::mlir::SmallVectorImpl<int64_t> &":$countPerRegion), [{}],
147      /*defaultImplementation=*/[{
148        unsigned numRegions = this->getOperation()->getNumRegions();
149        assert(countPerRegion.empty());
150        countPerRegion.resize(numRegions, kUnknownNumRegionInvocations);
151      }]
152    >
153  ];
154
155  let verify = [{
156    static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(),
157                  "expected operation to have non-zero regions");
158    return success();
159  }];
160
161  let extraClassDeclaration = [{
162    /// Convenience helper in case none of the operands is known.
163    void getSuccessorRegions(Optional<unsigned> index,
164                             SmallVectorImpl<RegionSuccessor> &regions) {
165       SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands());
166       getSuccessorRegions(index, nullAttrs, regions);
167    }
168
169    /// Verify types along control flow edges described by this interface.
170    static LogicalResult verifyTypes(Operation *op) {
171      return detail::verifyTypesAlongControlFlowEdges(op);
172    }
173  }];
174}
175
176//===----------------------------------------------------------------------===//
177// RegionBranchTerminatorOpInterface
178//===----------------------------------------------------------------------===//
179
180def RegionBranchTerminatorOpInterface :
181  OpInterface<"RegionBranchTerminatorOpInterface"> {
182  let description = [{
183    This interface provides information for branching terminator operations
184    in the presence of a parent RegionBranchOpInterface implementation. It
185    specifies which operands are passed to which successor region.
186  }];
187  let cppNamespace = "::mlir";
188
189  let methods = [
190    InterfaceMethod<[{
191        Returns a mutable range of operands that are semantically "returned" by
192        passing them to the region successor given by `index`.  If `index` is
193        None, this function returns the operands that are passed as a result to
194        the parent operation.
195      }],
196      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
197      (ins "::mlir::Optional<unsigned>":$index)
198    >,
199    InterfaceMethod<[{
200        Returns a range of operands that are semantically "returned" by passing
201        them to the region successor given by `index`.  If `index` is None, this
202        function returns the operands that are passed as a result to the parent
203        operation.
204      }],
205      "::mlir::OperandRange", "getSuccessorOperands",
206      (ins "::mlir::Optional<unsigned>":$index), [{}],
207      /*defaultImplementation=*/[{
208        return $_op.getMutableSuccessorOperands(index);
209      }]
210    >
211  ];
212
213  let verify = [{
214    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
215                  "expected operation to be a terminator");
216    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
217                  "expected operation to have zero results");
218    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
219                  "expected operation to have zero successors");
220    return success();
221  }];
222}
223
224//===----------------------------------------------------------------------===//
225// ControlFlow Traits
226//===----------------------------------------------------------------------===//
227
228// Op is "return-like".
229def ReturnLike : NativeOpTrait<"ReturnLike">;
230
231#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
232