1//===-- LLVMOpBase.td - LLVM IR dialect shared definitions -*- 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 shared definitions for the LLVM IR dialect and its 10// subdialects. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVMIR_OP_BASE 15#define LLVMIR_OP_BASE 16 17include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td" 18include "mlir/Dialect/LLVMIR/LLVMInterfaces.td" 19include "mlir/IR/OpBase.td" 20include "mlir/Interfaces/SideEffectInterfaces.td" 21 22//===----------------------------------------------------------------------===// 23// LLVM dialect type constraints. 24//===----------------------------------------------------------------------===// 25 26// LLVM dialect type. 27def LLVM_Type : DialectType<LLVM_Dialect, 28 CPred<"::mlir::LLVM::isCompatibleOuterType($_self)">, 29 "LLVM dialect-compatible type">; 30 31// Type constraint accepting LLVM token type. 32def LLVM_TokenType : Type< 33 CPred<"::llvm::isa<::mlir::LLVM::LLVMTokenType>($_self)">, 34 "LLVM token type">, 35 BuildableType<"::mlir::LLVM::LLVMTokenType::get($_builder.getContext())">; 36 37// Type constraint accepting LLVM primitive types, i.e. all types except void 38// and function. 39def LLVM_PrimitiveType : Type< 40 And<[LLVM_Type.predicate, 41 CPred<"!::llvm::isa<::mlir::LLVM::LLVMVoidType, " 42 "::mlir::LLVM::LLVMFunctionType>($_self)">]>, 43 "primitive LLVM type">; 44 45// Type constraint accepting any LLVM function type. 46def LLVM_FunctionType : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMFunctionType>($_self)">, 47 "LLVM function type", "::mlir::LLVM::LLVMFunctionType">; 48 49// Type constraint accepting any LLVM floating point type. 50def LLVM_AnyFloat : Type< 51 CPred<"::mlir::LLVM::isCompatibleFloatingPointType($_self)">, 52 "floating point LLVM type">; 53 54// Type constraint accepting any LLVM pointer type. 55def LLVM_AnyPointer : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMPointerType>($_self)">, 56 "LLVM pointer type", "::mlir::LLVM::LLVMPointerType">; 57 58// Pointer in a given address space. 59class LLVM_PointerInAddressSpace<int addressSpace> : Type< 60 And<[LLVM_AnyPointer.predicate, 61 CPred< 62 "::llvm::cast<::mlir::LLVM::LLVMPointerType>($_self).getAddressSpace() == " 63 # addressSpace>]>, 64 "LLVM pointer in address space " # addressSpace, 65 "::mlir::LLVM::LLVMPointerType"> { 66 let builderCall = "$_builder.getType<::mlir::LLVM::LLVMPointerType>(" 67 # addressSpace # ")"; 68} 69 70// Type constraint accepting an LLVM pointer type in address space 0. 71def LLVM_DefaultPointer : LLVM_PointerInAddressSpace<0>; 72 73// Type constraint accepting any LLVM structure type. 74def LLVM_AnyStruct : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMStructType>($_self)">, 75 "LLVM structure type">; 76 77// Type constraint accepting opaque LLVM structure type. 78def LLVM_OpaqueStruct : Type< 79 And<[LLVM_AnyStruct.predicate, 80 CPred<"::llvm::cast<::mlir::LLVM::LLVMStructType>($_self).isOpaque()">]>>; 81 82// Type constraint accepting any LLVM target extension type. 83def LLVM_AnyTargetExt : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMTargetExtType>($_self)">, 84 "LLVM target extension type">; 85 86// Type constraint accepting LLVM target extension types with no support for 87// memory operations such as alloca, load and store. 88def LLVM_NonLoadableTargetExtType : Type< 89 And<[LLVM_AnyTargetExt.predicate, 90 CPred<"!::llvm::cast<::mlir::LLVM::LLVMTargetExtType>($_self).supportsMemOps()">] 91 >>; 92 93// Type constraint accepting any LLVM type that can be loaded or stored, i.e. a 94// type that has size (not void, function, opaque struct type or target 95// extension type which does not support memory operations). 96def LLVM_LoadableType : Type< 97 Or<[And<[LLVM_PrimitiveType.predicate, Neg<LLVM_OpaqueStruct.predicate>, 98 Neg<LLVM_NonLoadableTargetExtType.predicate>]>, 99 LLVM_PointerElementTypeInterface.predicate]>, 100 "LLVM type with size">; 101 102// Type constraint accepting any LLVM aggregate type, i.e. structure or array. 103def LLVM_AnyAggregate : Type< 104 CPred<"::llvm::isa<::mlir::LLVM::LLVMStructType, " 105 "::mlir::LLVM::LLVMArrayType>($_self)">, 106 "LLVM aggregate type">; 107 108// Type constraint accepting any LLVM non-aggregate type, i.e. not structure or 109// array. 110def LLVM_AnyNonAggregate : Type<And<[LLVM_Type.predicate, 111 Neg<LLVM_AnyAggregate.predicate>]>, 112 "LLVM-compatible non-aggregate type">; 113 114// Type constraint accepting any LLVM vector type. 115def LLVM_AnyVector : Type<CPred<"::mlir::LLVM::isCompatibleVectorType($_self)">, 116 "LLVM dialect-compatible vector type">; 117 118// Type constraint accepting any LLVM fixed-length vector type. 119def LLVM_AnyFixedVector : Type<CPred< 120 "!::mlir::LLVM::isScalableVectorType($_self)">, 121 "LLVM dialect-compatible fixed-length vector type">; 122 123// Type constraint accepting any LLVM scalable vector type. 124def LLVM_AnyScalableVector : Type<CPred< 125 "::mlir::LLVM::isScalableVectorType($_self)">, 126 "LLVM dialect-compatible scalable vector type">; 127 128// Type constraint accepting an LLVM vector type with an additional constraint 129// on the vector element type. 130class LLVM_VectorOf<Type element> : Type< 131 And<[LLVM_AnyVector.predicate, 132 SubstLeaves< 133 "$_self", 134 "::mlir::LLVM::getVectorElementType($_self)", 135 element.predicate>]>, 136 "LLVM dialect-compatible vector of " # element.summary>; 137 138// Type constraint accepting a constrained type, or a vector of such types. 139class LLVM_ScalarOrVectorOf<Type element> : 140 AnyTypeOf<[element, LLVM_VectorOf<element>]>; 141 142// Base class for LLVM operations. Defines the interface to the llvm::IRBuilder 143// used to translate to proper LLVM IR and the interface to the mlir::OpBuilder 144// used to import from LLVM IR. 145class LLVM_OpBase<Dialect dialect, string mnemonic, list<Trait> traits = []> : 146 Op<dialect, mnemonic, traits> { 147 // A pattern for constructing the LLVM IR Instruction (or other Value) that 148 // corresponds to this op. This pattern can use `builder` to refer to an 149 // `llvm::IRBuilder<>` instance, $-names of arguments and results and the 150 // following special variable names: 151 // - $_resultType - substituted with the LLVM IR type of the result; 152 // - $_numOperands - substituted with the number of operands (including 153 // the variadic ones); 154 // - $_hasResult - substituted with a check that a variadic-result op does 155 // have a result (LLVM ops can have 0 or 1 result); 156 // - $_location - mlir::Location object of the instruction. 157 // Additionally, `$$` can be used to produce the dollar character. 158 string llvmBuilder = ""; 159 160 // A builder to construct the MLIR LLVM dialect operation given the matching 161 // LLVM IR instruction `inst` and its operands `llvmOperands`. The 162 // following $-variables exist: 163 // - $name - substituted by the remapped `inst` operand value at the index 164 // of the MLIR operation argument with the given name, or if the 165 // name matches the result name, by a reference to store the 166 // result of the newly created MLIR operation to; 167 // - $_op - substituted by a reference to store the newly created MLIR 168 // operation (only for MLIR operations that return no result); 169 // - $_int_attr - substituted by a call to an integer attribute matcher; 170 // - $_float_attr - substituted by a call to a float attribute matcher; 171 // - $_var_attr - substituted by a call to a variable attribute matcher; 172 // - $_label_attr - substituted by a call to a label attribute matcher; 173 // - $_roundingMode_attr - substituted by a call to a rounding mode 174 // attribute matcher; 175 // - $_fpExceptionBehavior_attr - substituted by a call to a FP exception 176 // behavior attribute matcher; 177 // - $_resultType - substituted with the MLIR result type; 178 // - $_location - substituted with the MLIR location; 179 // - $_builder - substituted with the MLIR builder; 180 // - $_qualCppClassName - substitiuted with the MLIR operation class name. 181 // Always either store a reference to the result of the newly created 182 // operation, or to the operation itself if it does not return a result. 183 // Additionally, `$$` can be used to produce the dollar character. 184 string mlirBuilder = ""; 185 186 // An array that specifies a mapping from MLIR argument indices to LLVM IR 187 // operand indices. The mapping is necessary since argument and operand 188 // indices do not always match. If not defined, the array is set to the 189 // identity permutation. An operation may define any custom index permutation 190 // and set a specific argument index to -1 if it does not map to an LLVM IR 191 // operand. 192 list<int> llvmArgIndices = []; 193} 194 195//===----------------------------------------------------------------------===// 196// Patterns for LLVM dialect operations. 197//===----------------------------------------------------------------------===// 198 199// Patterns with code to set flags and metadata of memory operations after their 200// translation to LLVM IR instructions. Operations may use the patterns to 201// implement their "llvmBuilder". The patterns assume the `op` and `inst` 202// variables exist and refer to the original MLIR operation and the translated 203// LLVM IR instruction, respectively. 204class LLVM_MemOpPatterns { 205 code setAlignmentCode = [{ 206 if ($alignment.has_value()) { 207 auto align = *$alignment; 208 if (align != 0) 209 inst->setAlignment(llvm::Align(align)); 210 } 211 }]; 212 code setVolatileCode = [{ 213 inst->setVolatile($volatile_); 214 }]; 215 code setSyncScopeCode = [{ 216 if ($syncscope.has_value()) { 217 llvm::LLVMContext &llvmContext = builder.getContext(); 218 inst->setSyncScopeID(llvmContext.getOrInsertSyncScopeID(*$syncscope)); 219 } 220 }]; 221 code setOrderingCode = [{ 222 inst->setAtomic(convertAtomicOrderingToLLVM($ordering)); 223 }]; 224 code setNonTemporalMetadataCode = [{ 225 if ($nontemporal) { 226 llvm::MDNode *metadata = llvm::MDNode::get( 227 inst->getContext(), llvm::ConstantAsMetadata::get( 228 builder.getInt32(1))); 229 inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata); 230 } 231 }]; 232 code setInvariantGroupCode = [{ 233 if ($invariantGroup) { 234 llvm::MDNode *metadata = llvm::MDNode::get(inst->getContext(), 235 std::nullopt); 236 inst->setMetadata(llvm::LLVMContext::MD_invariant_group, metadata); 237 } 238 }]; 239 code setAccessGroupsMetadataCode = [{ 240 moduleTranslation.setAccessGroupsMetadata(op, inst); 241 }]; 242 code setAliasAnalysisMetadataCode = [{ 243 moduleTranslation.setAliasScopeMetadata(op, inst); 244 moduleTranslation.setTBAAMetadata(op, inst); 245 }]; 246} 247 248//===----------------------------------------------------------------------===// 249// Base classes for LLVM dialect operations. 250//===----------------------------------------------------------------------===// 251 252// Base class for LLVM operations. All operations get an "llvm." prefix in 253// their name automatically and should either have zero or one result. 254class LLVM_Op<string mnemonic, list<Trait> traits = []> : 255 LLVM_OpBase<LLVM_Dialect, mnemonic, traits>; 256 257// Base class for LLVM memory access operations that implement the access group 258// and alias analysis interfaces. The "aliasAttrs" list contains the arguments 259// required by the access group and alias analysis interfaces. Derived 260// operations should append the "aliasAttrs" to their argument list. 261class LLVM_MemAccessOpBase<string mnemonic, list<Trait> traits = []> : 262 LLVM_Op<mnemonic, !listconcat([ 263 DeclareOpInterfaceMethods<AccessGroupOpInterface>, 264 DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], traits)>, 265 LLVM_MemOpPatterns { 266 dag aliasAttrs = (ins OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups, 267 OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes, 268 OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes, 269 OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa); 270} 271 272// Base class for LLVM intrinsics operation. It is similar to LLVM_Op, but 273// provides the "llvmBuilder" field for constructing the intrinsic. 274// The builder relies on the contents of "overloadedResults" and 275// "overloadedOperands" lists that contain the positions of intrinsic results 276// and operands that are overloadable in the LLVM sense, that is their types 277// must be passed in during the construction of the intrinsic declaration to 278// differentiate between differently-typed versions of the intrinsic. 279// If the intrinsic has multiple results, this will eventually be packed into a 280// single struct result. In this case, the types of any overloaded results need 281// to be accessed via the LLVMStructType, instead of directly via the result. 282// "opName" contains the name of the operation to be associated with the 283// intrinsic and "enumName" contains the name of the intrinsic as appears in 284// `llvm::Intrinsic` enum; one usually wants these to be related. Additionally, 285// the base class also defines the "mlirBuilder" field to support the inverse 286// translation starting from an LLVM IR intrinsic. The "requiresAccessGroup", 287// "requiresAliasAnalysis", and "requiresFastmath" flags specify which 288// interfaces the intrinsic implements. If the corresponding flags are set, the 289// "aliasAttrs" list contains the arguments required by the access group and 290// alias analysis interfaces. Derived intrinsics should append the "aliasAttrs" 291// to their argument list if they set one of the flags. LLVM `immargs` can be 292// represented as MLIR attributes by providing both the `immArgPositions` and 293// `immArgAttrNames` lists. These two lists should have equal length, with 294// `immArgPositions` containing the argument positions on the LLVM IR attribute 295// that are `immargs`, and `immArgAttrNames` mapping these to corresponding 296// MLIR attributes. 297class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName, 298 list<int> overloadedResults, list<int> overloadedOperands, 299 list<Trait> traits, int numResults, 300 bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0, 301 bit requiresFastmath = 0, bit requiresOpBundles = 0, 302 list<int> immArgPositions = [], 303 list<string> immArgAttrNames = []> 304 : LLVM_OpBase<dialect, opName, !listconcat( 305 !if(!gt(requiresAccessGroup, 0), 306 [DeclareOpInterfaceMethods<AccessGroupOpInterface>], []), 307 !if(!gt(requiresAliasAnalysis, 0), 308 [DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], []), 309 !if(!gt(requiresFastmath, 0), 310 [DeclareOpInterfaceMethods<FastmathFlagsInterface>], []), 311 traits)>, 312 LLVM_MemOpPatterns, 313 Results<!if(!gt(numResults, 0), (outs LLVM_Type:$res), (outs))> { 314 dag aliasAttrs = !con( 315 !if(!gt(requiresAccessGroup, 0), 316 (ins OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups), 317 (ins )), 318 !if(!gt(requiresAliasAnalysis, 0), 319 (ins OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes, 320 OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes, 321 OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa), 322 (ins ))); 323 dag opBundleArgs = !if(!gt(requiresOpBundles, 0), 324 (ins VariadicOfVariadic<LLVM_Type, 325 "op_bundle_sizes">:$op_bundle_operands, 326 DenseI32ArrayAttr:$op_bundle_sizes, 327 OptionalAttr<ArrayAttr>:$op_bundle_tags), 328 (ins )); 329 string llvmEnumName = enumName; 330 string overloadedResultsCpp = "{" # !interleave(overloadedResults, ", ") # "}"; 331 string overloadedOperandsCpp = "{" # !interleave(overloadedOperands, ", ") # "}"; 332 string immArgPositionsCpp = "{" # !interleave(immArgPositions, ", ") # "}"; 333 string immArgAttrNamesCpp = "{" # !interleave(!foreach(name, immArgAttrNames, 334 "StringLiteral(\"" # name # "\")"), ", ") # "}"; 335 string baseLlvmBuilder = [{ 336 auto *inst = LLVM::detail::createIntrinsicCall( 337 builder, moduleTranslation, &opInst, llvm::Intrinsic::}] # !interleave([ 338 enumName, "" # numResults, overloadedResultsCpp, overloadedOperandsCpp, 339 immArgPositionsCpp, immArgAttrNamesCpp], ",") # [{); 340 (void) inst; 341 }]; 342 string baseLlvmBuilderCoda = !if(!gt(numResults, 0), "$res = inst;", ""); 343 let llvmBuilder = baseLlvmBuilder # !if(!gt(requiresAccessGroup, 0), setAccessGroupsMetadataCode, "") 344 # !if(!gt(requiresAliasAnalysis, 0), setAliasAnalysisMetadataCode, "") 345 # baseLlvmBuilderCoda; 346 347 string baseMlirBuilder = [{ 348 SmallVector<Value> mlirOperands; 349 SmallVector<NamedAttribute> mlirAttrs; 350 if (failed(moduleImport.convertIntrinsicArguments( 351 llvmOperands, 352 llvmOpBundles, 353 }] # !if(!gt(requiresOpBundles, 0), "true", "false") # [{, 354 }] # immArgPositionsCpp # [{, 355 }] # immArgAttrNamesCpp # [{, 356 mlirOperands, 357 mlirAttrs)) 358 ) { 359 return failure(); 360 } 361 SmallVector<Type> resultTypes = 362 }] # !if(!gt(numResults, 0), "{$_resultType};", "{};") # [{ 363 auto op = $_builder.create<$_qualCppClassName>( 364 $_location, resultTypes, mlirOperands, mlirAttrs); 365 }]; 366 string baseMlirBuilderCoda = !if(!gt(numResults, 0), "$res = op;", "$_op = op;"); 367 let mlirBuilder = baseMlirBuilder # !if(!gt(requiresFastmath, 0), 368 "moduleImport.setFastmathFlagsAttr(inst, op);", "") 369 # baseMlirBuilderCoda; 370 371 // Code for handling a `range` attribute that holds the constant range of the 372 // intrinsic's result (if one is specified at the call site). This is intended 373 // for GPU IDs and other calls where range() is meaningful. It expects 374 // an optional LLVM_ConstantRangeAttr named `range` to be present on the 375 // operation. These are included to abstract out common code in several 376 // dialects. 377 string setRangeRetAttrCode = [{ 378 if ($range) { 379 inst->addRangeRetAttr(::llvm::ConstantRange( 380 $range->getLower(), $range->getUpper())); 381 } 382 }]; 383 string importRangeRetAttrCode = [{ 384 // Note: we don't want to look in to the declaration here. 385 auto rangeAttr = inst->getAttributes().getRetAttr(::llvm::Attribute::Range); 386 if (rangeAttr.isValid()) { 387 const ::llvm::ConstantRange& value = rangeAttr.getValueAsConstantRange(); 388 op.setRangeAttr(::mlir::LLVM::ConstantRangeAttr::get($_builder.getContext(), value.getLower(), value.getUpper())); 389 } 390 }]; 391} 392 393// Base class for LLVM intrinsic operations, should not be used directly. Places 394// the intrinsic into the LLVM dialect and prefixes its name with "intr.". 395class LLVM_IntrOp<string mnem, list<int> overloadedResults, 396 list<int> overloadedOperands, list<Trait> traits, 397 int numResults, bit requiresAccessGroup = 0, 398 bit requiresAliasAnalysis = 0, bit requiresFastmath = 0, 399 bit requiresOpBundles = 0, 400 list<int> immArgPositions = [], 401 list<string> immArgAttrNames = []> 402 : LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem), 403 overloadedResults, overloadedOperands, traits, 404 numResults, requiresAccessGroup, requiresAliasAnalysis, 405 requiresFastmath, requiresOpBundles, immArgPositions, 406 immArgAttrNames>; 407 408// Base class for LLVM intrinsic operations returning no results. Places the 409// intrinsic into the LLVM dialect and prefixes its name with "intr.". 410// 411// Sample use: derive an entry from this class and populate the fields. 412// 413// def LLVM_Name : LLVM_ZeroResultIntrOp<"name", [0], [Pure]>, 414// Arguments<(ins LLVM_Type, LLVM_Type)>; 415// 416// The mnemonic will be prefixed with "llvm.intr.", where the "llvm." part comes 417// from the LLVM dialect. The overloadedOperands list contains the indices of 418// the operands the type of which will be passed in the LLVM IR intrinsic 419// builder. In the example above, the Op has two arguments, but only the first 420// one (as indicated by `[0]`) is necessary to resolve the overloaded intrinsic. 421// The Op has no results. 422class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [], 423 list<Trait> traits = [], 424 bit requiresAccessGroup = 0, 425 bit requiresAliasAnalysis = 0, 426 bit requiresOpBundles = 0, 427 list<int> immArgPositions = [], 428 list<string> immArgAttrNames = []> 429 : LLVM_IntrOp<mnem, [], overloadedOperands, traits, /*numResults=*/0, 430 requiresAccessGroup, requiresAliasAnalysis, 431 /*requiresFastMath=*/0, requiresOpBundles, immArgPositions, 432 immArgAttrNames>; 433 434// Base class for LLVM intrinsic operations returning one result. Places the 435// intrinsic into the LLVM dialect and prefixes its name with "intr.". This is 436// similar to LLVM_ZeroResultIntrOp but allows one to define Ops returning one 437// result, called "res". Additionally, the overloadedResults list should contain 438// "0" if the result must be used to resolve overloaded intrinsics, or remain 439// empty otherwise. 440class LLVM_OneResultIntrOp<string mnem, list<int> overloadedResults = [], 441 list<int> overloadedOperands = [], 442 list<Trait> traits = [], 443 bit requiresFastmath = 0, 444 list<int> immArgPositions = [], 445 list<string> immArgAttrNames = []> 446 : LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 1, 447 /*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0, 448 requiresFastmath, /*requiresOpBundles=*/0, immArgPositions, 449 immArgAttrNames>; 450 451def LLVM_OneResultOpBuilder : 452 OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, 453 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 454 [{ 455 if (resultType) $_state.addTypes(resultType); 456 $_state.addOperands(operands); 457 for (auto namedAttr : attributes) 458 $_state.addAttribute(namedAttr.getName(), namedAttr.getValue()); 459 }]>; 460 461def LLVM_ZeroResultOpBuilder : 462 OpBuilder<(ins "ValueRange":$operands, 463 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 464 [{ 465 $_state.addOperands(operands); 466 for (auto namedAttr : attributes) 467 $_state.addAttribute(namedAttr.getName(), namedAttr.getValue()); 468 }]>; 469 470// Compatibility builder that takes an instance of wrapped llvm::VoidType 471// to indicate no result. 472def LLVM_VoidResultTypeOpBuilder : 473 OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, 474 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 475 [{ 476 assert(isCompatibleType(resultType) && "result must be an LLVM type"); 477 assert(::llvm::isa<LLVMVoidType>(resultType) && 478 "for zero-result operands, only 'void' is accepted as result type"); 479 build($_builder, $_state, operands, attributes); 480 }]>; 481 482 483// Opaque builder used for terminator operations that contain successors. 484def LLVM_TerminatorPassthroughOpBuilder : 485 OpBuilder<(ins "ValueRange":$operands, "SuccessorRange":$destinations, 486 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 487 [{ 488 $_state.addOperands(operands); 489 $_state.addSuccessors(destinations); 490 $_state.addAttributes(attributes); 491 }]>; 492 493 494#endif // LLVMIR_OP_BASE 495