1//===- ControlFlowOps.td - ControlFlow operations ----------*- 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 definitions for the operations within the ControlFlow 10// dialect. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef MLIR_DIALECTS_CONTROLFLOW_IR_CONTROLFLOWOPS_TD 15#define MLIR_DIALECTS_CONTROLFLOW_IR_CONTROLFLOWOPS_TD 16 17include "mlir/IR/EnumAttr.td" 18include "mlir/IR/OpAsmInterface.td" 19include "mlir/Interfaces/ControlFlowInterfaces.td" 20include "mlir/Interfaces/SideEffectInterfaces.td" 21 22def ControlFlow_Dialect : Dialect { 23 let name = "cf"; 24 let cppNamespace = "::mlir::cf"; 25 let dependentDialects = ["arith::ArithmeticDialect"]; 26 let emitAccessorPrefix = kEmitAccessorPrefix_Prefixed; 27 let description = [{ 28 This dialect contains low-level, i.e. non-region based, control flow 29 constructs. These constructs generally represent control flow directly 30 on SSA blocks of a control flow graph. 31 }]; 32} 33 34class CF_Op<string mnemonic, list<Trait> traits = []> : 35 Op<ControlFlow_Dialect, mnemonic, traits>; 36 37//===----------------------------------------------------------------------===// 38// AssertOp 39//===----------------------------------------------------------------------===// 40 41def AssertOp : CF_Op<"assert"> { 42 let summary = "Assert operation with message attribute"; 43 let description = [{ 44 Assert operation with single boolean operand and an error message attribute. 45 If the argument is `true` this operation has no effect. Otherwise, the 46 program execution will abort. The provided error message may be used by a 47 runtime to propagate the error to the user. 48 49 Example: 50 51 ```mlir 52 assert %b, "Expected ... to be true" 53 ``` 54 }]; 55 56 let arguments = (ins I1:$arg, StrAttr:$msg); 57 58 let assemblyFormat = "$arg `,` $msg attr-dict"; 59 let hasCanonicalizeMethod = 1; 60} 61 62//===----------------------------------------------------------------------===// 63// BranchOp 64//===----------------------------------------------------------------------===// 65 66def BranchOp : CF_Op<"br", [ 67 DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>, 68 NoSideEffect, Terminator 69 ]> { 70 let summary = "branch operation"; 71 let description = [{ 72 The `cf.br` operation represents a direct branch operation to a given 73 block. The operands of this operation are forwarded to the successor block, 74 and the number and type of the operands must match the arguments of the 75 target block. 76 77 Example: 78 79 ```mlir 80 ^bb2: 81 %2 = call @someFn() 82 cf.br ^bb3(%2 : tensor<*xf32>) 83 ^bb3(%3: tensor<*xf32>): 84 ``` 85 }]; 86 87 let arguments = (ins Variadic<AnyType>:$destOperands); 88 let successors = (successor AnySuccessor:$dest); 89 90 let builders = [ 91 OpBuilder<(ins "Block *":$dest, 92 CArg<"ValueRange", "{}">:$destOperands), [{ 93 $_state.addSuccessors(dest); 94 $_state.addOperands(destOperands); 95 }]>]; 96 97 let extraClassDeclaration = [{ 98 void setDest(Block *block); 99 100 /// Erase the operand at 'index' from the operand list. 101 void eraseOperand(unsigned index); 102 }]; 103 104 let hasCanonicalizeMethod = 1; 105 let assemblyFormat = [{ 106 $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict 107 }]; 108} 109 110//===----------------------------------------------------------------------===// 111// CondBranchOp 112//===----------------------------------------------------------------------===// 113 114def CondBranchOp : CF_Op<"cond_br", 115 [AttrSizedOperandSegments, 116 DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>, 117 NoSideEffect, Terminator]> { 118 let summary = "conditional branch operation"; 119 let description = [{ 120 The `cond_br` terminator operation represents a conditional branch on a 121 boolean (1-bit integer) value. If the bit is set, then the first destination 122 is jumped to; if it is false, the second destination is chosen. The count 123 and types of operands must align with the arguments in the corresponding 124 target blocks. 125 126 The MLIR conditional branch operation is not allowed to target the entry 127 block for a region. The two destinations of the conditional branch operation 128 are allowed to be the same. 129 130 The following example illustrates a function with a conditional branch 131 operation that targets the same block. 132 133 Example: 134 135 ```mlir 136 func.func @select(%a: i32, %b: i32, %flag: i1) -> i32 { 137 // Both targets are the same, operands differ 138 cond_br %flag, ^bb1(%a : i32), ^bb1(%b : i32) 139 140 ^bb1(%x : i32) : 141 return %x : i32 142 } 143 ``` 144 }]; 145 146 let arguments = (ins I1:$condition, 147 Variadic<AnyType>:$trueDestOperands, 148 Variadic<AnyType>:$falseDestOperands); 149 let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest); 150 151 let builders = [ 152 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 153 "ValueRange":$trueOperands, "Block *":$falseDest, 154 "ValueRange":$falseOperands), [{ 155 build($_builder, $_state, condition, trueOperands, falseOperands, trueDest, 156 falseDest); 157 }]>, 158 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 159 "Block *":$falseDest, CArg<"ValueRange", "{}">:$falseOperands), [{ 160 build($_builder, $_state, condition, trueDest, ValueRange(), falseDest, 161 falseOperands); 162 }]>]; 163 164 let extraClassDeclaration = [{ 165 // These are the indices into the dests list. 166 enum { trueIndex = 0, falseIndex = 1 }; 167 168 // Accessors for operands to the 'true' destination. 169 Value getTrueOperand(unsigned idx) { 170 assert(idx < getNumTrueOperands()); 171 return getOperand(getTrueDestOperandIndex() + idx); 172 } 173 174 void setTrueOperand(unsigned idx, Value value) { 175 assert(idx < getNumTrueOperands()); 176 setOperand(getTrueDestOperandIndex() + idx, value); 177 } 178 179 unsigned getNumTrueOperands() { return getTrueOperands().size(); } 180 181 /// Erase the operand at 'index' from the true operand list. 182 void eraseTrueOperand(unsigned index) { 183 getTrueDestOperandsMutable().erase(index); 184 } 185 186 // Accessors for operands to the 'false' destination. 187 Value getFalseOperand(unsigned idx) { 188 assert(idx < getNumFalseOperands()); 189 return getOperand(getFalseDestOperandIndex() + idx); 190 } 191 void setFalseOperand(unsigned idx, Value value) { 192 assert(idx < getNumFalseOperands()); 193 setOperand(getFalseDestOperandIndex() + idx, value); 194 } 195 196 operand_range getTrueOperands() { return getTrueDestOperands(); } 197 operand_range getFalseOperands() { return getFalseDestOperands(); } 198 199 unsigned getNumFalseOperands() { return getFalseOperands().size(); } 200 201 /// Erase the operand at 'index' from the false operand list. 202 void eraseFalseOperand(unsigned index) { 203 getFalseDestOperandsMutable().erase(index); 204 } 205 206 private: 207 /// Get the index of the first true destination operand. 208 unsigned getTrueDestOperandIndex() { return 1; } 209 210 /// Get the index of the first false destination operand. 211 unsigned getFalseDestOperandIndex() { 212 return getTrueDestOperandIndex() + getNumTrueOperands(); 213 } 214 }]; 215 216 let hasCanonicalizer = 1; 217 let assemblyFormat = [{ 218 $condition `,` 219 $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,` 220 $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)? 221 attr-dict 222 }]; 223} 224 225//===----------------------------------------------------------------------===// 226// SwitchOp 227//===----------------------------------------------------------------------===// 228 229def SwitchOp : CF_Op<"switch", 230 [AttrSizedOperandSegments, 231 DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>, 232 NoSideEffect, Terminator]> { 233 let summary = "switch operation"; 234 let description = [{ 235 The `switch` terminator operation represents a switch on a signless integer 236 value. If the flag matches one of the specified cases, then the 237 corresponding destination is jumped to. If the flag does not match any of 238 the cases, the default destination is jumped to. The count and types of 239 operands must align with the arguments in the corresponding target blocks. 240 241 Example: 242 243 ```mlir 244 switch %flag : i32, [ 245 default: ^bb1(%a : i32), 246 42: ^bb1(%b : i32), 247 43: ^bb3(%c : i32) 248 ] 249 ``` 250 }]; 251 252 let arguments = (ins 253 AnyInteger:$flag, 254 Variadic<AnyType>:$defaultOperands, 255 VariadicOfVariadic<AnyType, "case_operand_segments">:$caseOperands, 256 OptionalAttr<AnyIntElementsAttr>:$case_values, 257 I32ElementsAttr:$case_operand_segments 258 ); 259 let successors = (successor 260 AnySuccessor:$defaultDestination, 261 VariadicSuccessor<AnySuccessor>:$caseDestinations 262 ); 263 let builders = [ 264 OpBuilder<(ins "Value":$flag, 265 "Block *":$defaultDestination, 266 "ValueRange":$defaultOperands, 267 CArg<"ArrayRef<APInt>", "{}">:$caseValues, 268 CArg<"BlockRange", "{}">:$caseDestinations, 269 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands)>, 270 OpBuilder<(ins "Value":$flag, 271 "Block *":$defaultDestination, 272 "ValueRange":$defaultOperands, 273 CArg<"ArrayRef<int32_t>", "{}">:$caseValues, 274 CArg<"BlockRange", "{}">:$caseDestinations, 275 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands)>, 276 OpBuilder<(ins "Value":$flag, 277 "Block *":$defaultDestination, 278 "ValueRange":$defaultOperands, 279 CArg<"DenseIntElementsAttr", "{}">:$caseValues, 280 CArg<"BlockRange", "{}">:$caseDestinations, 281 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands)> 282 ]; 283 284 let assemblyFormat = [{ 285 $flag `:` type($flag) `,` `[` `\n` 286 custom<SwitchOpCases>(ref(type($flag)),$defaultDestination, 287 $defaultOperands, 288 type($defaultOperands), 289 $case_values, 290 $caseDestinations, 291 $caseOperands, 292 type($caseOperands)) 293 `]` 294 attr-dict 295 }]; 296 297 let extraClassDeclaration = [{ 298 /// Return the operands for the case destination block at the given index. 299 OperandRange getCaseOperands(unsigned index) { 300 return getCaseOperands()[index]; 301 } 302 303 /// Return a mutable range of operands for the case destination block at the 304 /// given index. 305 MutableOperandRange getCaseOperandsMutable(unsigned index) { 306 return getCaseOperandsMutable()[index]; 307 } 308 }]; 309 310 let hasCanonicalizer = 1; 311 let hasVerifier = 1; 312} 313 314#endif // MLIR_DIALECTS_CONTROLFLOW_IR_CONTROLFLOWOPS_TD 315