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