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