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  ];
134
135  let verify = [{
136    static_assert(!ConcreteOp::template hasTrait<OpTrait::ZeroRegion>(),
137                  "expected operation to have non-zero regions");
138    return success();
139  }];
140
141  let extraClassDeclaration = [{
142    /// Convenience helper in case none of the operands is known.
143    void getSuccessorRegions(Optional<unsigned> index,
144                             SmallVectorImpl<RegionSuccessor> &regions) {
145       SmallVector<Attribute, 2> nullAttrs(getOperation()->getNumOperands());
146       getSuccessorRegions(index, nullAttrs, regions);
147    }
148
149    /// Verify types along control flow edges described by this interface.
150    static LogicalResult verifyTypes(Operation *op) {
151      return detail::verifyTypesAlongControlFlowEdges(op);
152    }
153  }];
154}
155
156//===----------------------------------------------------------------------===//
157// RegionBranchTerminatorOpInterface
158//===----------------------------------------------------------------------===//
159
160def RegionBranchTerminatorOpInterface :
161  OpInterface<"RegionBranchTerminatorOpInterface"> {
162  let description = [{
163    This interface provides information for branching terminator operations
164    in the presence of a parent RegionBranchOpInterface implementation. It
165    specifies which operands are passed to which successor region.
166  }];
167  let cppNamespace = "::mlir";
168
169  let methods = [
170    InterfaceMethod<[{
171        Returns a mutable range of operands that are semantically "returned" by
172        passing them to the region successor given by `index`.  If `index` is
173        None, this function returns the operands that are passed as a result to
174        the parent operation.
175      }],
176      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
177      (ins "::mlir::Optional<unsigned>":$index)
178    >,
179    InterfaceMethod<[{
180        Returns a range of operands that are semantically "returned" by passing
181        them to the region successor given by `index`.  If `index` is None, this
182        function returns the operands that are passed as a result to the parent
183        operation.
184      }],
185      "::mlir::OperandRange", "getSuccessorOperands",
186      (ins "::mlir::Optional<unsigned>":$index), [{}],
187      /*defaultImplementation=*/[{
188        return $_op.getMutableSuccessorOperands(index);
189      }]
190    >
191  ];
192
193  let verify = [{
194    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
195                  "expected operation to be a terminator");
196    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
197                  "expected operation to have zero results");
198    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
199                  "expected operation to have zero successors");
200    return success();
201  }];
202}
203
204//===----------------------------------------------------------------------===//
205// ControlFlow Traits
206//===----------------------------------------------------------------------===//
207
208// Op is "return-like".
209def ReturnLike : NativeOpTrait<"ReturnLike">;
210
211#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
212