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> ®ions) { 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