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      "Optional<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      "Optional<OperandRange>", "getSuccessorOperands",
47      (ins "unsigned":$index), [{}], [{
48        ConcreteOp *op = static_cast<ConcreteOp *>(this);
49        auto operands = op->getMutableSuccessorOperands(index);
50        return operands ? Optional<OperandRange>(*operands) : llvm::None;
51      }]
52    >,
53    InterfaceMethod<[{
54        Returns the `BlockArgument` corresponding to operand `operandIndex` in
55        some successor, or None if `operandIndex` isn't a successor operand
56        index.
57      }],
58      "Optional<BlockArgument>", "getSuccessorBlockArgument",
59      (ins "unsigned":$operandIndex), [{
60        Operation *opaqueOp = $_op;
61        for (unsigned i = 0, e = opaqueOp->getNumSuccessors(); i != e; ++i) {
62          if (Optional<BlockArgument> arg = detail::getBranchSuccessorArgument(
63                $_op.getSuccessorOperands(i), operandIndex,
64                opaqueOp->getSuccessor(i)))
65            return arg;
66        }
67        return llvm::None;
68      }]
69    >,
70    InterfaceMethod<[{
71        Returns the successor that would be chosen with the given constant
72        operands. Returns nullptr if a single successor could not be chosen.
73      }],
74      "Block *", "getSuccessorForOperands",
75      (ins "ArrayRef<Attribute>":$operands), [{}],
76      /*defaultImplementation=*/[{ return nullptr; }]
77    >
78  ];
79
80  let verify = [{
81    auto concreteOp = cast<ConcreteOpType>($_op);
82    for (unsigned i = 0, e = $_op->getNumSuccessors(); i != e; ++i) {
83      Optional<OperandRange> operands = concreteOp.getSuccessorOperands(i);
84      if (failed(detail::verifyBranchSuccessorOperands($_op, i, operands)))
85        return failure();
86    }
87    return success();
88  }];
89}
90
91//===----------------------------------------------------------------------===//
92// RegionBranchOpInterface
93//===----------------------------------------------------------------------===//
94
95def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
96  let description = [{
97    This interface provides information for region operations that contain
98    branching behavior between held regions, i.e. this interface allows for
99    expressing control flow information for region holding operations.
100  }];
101  let cppNamespace = "::mlir";
102
103  let methods = [
104    InterfaceMethod<[{
105        Returns the operands of this operation used as the entry arguments when
106        entering the region at `index`, which was specified as a successor of this
107        operation by `getSuccessorRegions`. These operands should correspond 1-1
108        with the successor inputs specified in `getSuccessorRegions`.
109      }],
110      "OperandRange", "getSuccessorEntryOperands",
111      (ins "unsigned":$index), [{}], /*defaultImplementation=*/[{
112        auto operandEnd = this->getOperation()->operand_end();
113        return 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 exit 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 "Optional<unsigned>":$index, "ArrayRef<Attribute>":$operands,
132           "SmallVectorImpl<RegionSuccessor> &":$regions)
133    >
134  ];
135
136  let verify = [{
137    static_assert(!ConcreteOpType::template hasTrait<OpTrait::ZeroRegion>(),
138                  "expected operation to have non-zero regions");
139    return success();
140  }];
141
142  let extraClassDeclaration = [{
143    /// Verify types along control flow edges described by this interface.
144    static LogicalResult verifyTypes(Operation *op) {
145      return detail::verifyTypesAlongControlFlowEdges(op);
146    }
147  }];
148}
149
150//===----------------------------------------------------------------------===//
151// ControlFlow Traits
152//===----------------------------------------------------------------------===//
153
154// Op is "return-like".
155def ReturnLike : NativeOpTrait<"ReturnLike">;
156
157#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES
158