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