1//===-- LLVMOps.td - LLVM IR dialect op definition file ----*- 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 is the LLVM IR operation definition file. 10// 11//===----------------------------------------------------------------------===// 12 13#ifndef LLVMIR_OPS 14#define LLVMIR_OPS 15 16include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td" 17include "mlir/Dialect/LLVMIR/LLVMEnums.td" 18include "mlir/Dialect/LLVMIR/LLVMOpBase.td" 19include "mlir/IR/EnumAttr.td" 20include "mlir/Interfaces/FunctionInterfaces.td" 21include "mlir/IR/SymbolInterfaces.td" 22include "mlir/Interfaces/CallInterfaces.td" 23include "mlir/Interfaces/ControlFlowInterfaces.td" 24include "mlir/Interfaces/InferTypeOpInterface.td" 25include "mlir/Interfaces/MemorySlotInterfaces.td" 26include "mlir/Interfaces/SideEffectInterfaces.td" 27include "mlir/Interfaces/ViewLikeInterface.td" 28 29class LLVM_Builder<string builder> { 30 string llvmBuilder = builder; 31} 32 33// Base class for LLVM terminator operations. All terminator operations have 34// zero results and an optional list of successors. 35class LLVM_TerminatorOp<string mnemonic, list<Trait> traits = []> : 36 LLVM_Op<mnemonic, !listconcat(traits, [Terminator])>; 37 38// Class for arithmetic binary operations. 39class LLVM_ArithmeticOpBase<Type type, string mnemonic, 40 string instName, list<Trait> traits = []> : 41 LLVM_Op<mnemonic, 42 !listconcat([Pure, SameOperandsAndResultType], traits)>, 43 LLVM_Builder<"$res = builder.Create" # instName # "($lhs, $rhs);"> { 44 dag commonArgs = (ins LLVM_ScalarOrVectorOf<type>:$lhs, 45 LLVM_ScalarOrVectorOf<type>:$rhs); 46 let results = (outs LLVM_ScalarOrVectorOf<type>:$res); 47 let builders = [LLVM_OneResultOpBuilder]; 48 let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($res)"; 49 string llvmInstName = instName; 50} 51class LLVM_IntArithmeticOp<string mnemonic, string instName, 52 list<Trait> traits = []> : 53 LLVM_ArithmeticOpBase<AnySignlessInteger, mnemonic, instName, traits> { 54 let arguments = commonArgs; 55 string mlirBuilder = [{ 56 $res = $_builder.create<$_qualCppClassName>($_location, $lhs, $rhs); 57 }]; 58} 59class LLVM_IntArithmeticOpWithOverflowFlag<string mnemonic, string instName, 60 list<Trait> traits = []> : 61 LLVM_ArithmeticOpBase<AnySignlessInteger, mnemonic, instName, 62 !listconcat([DeclareOpInterfaceMethods<IntegerOverflowFlagsInterface>], traits)> { 63 dag iofArg = (ins EnumProp<"IntegerOverflowFlags", "", "IntegerOverflowFlags::none">:$overflowFlags); 64 let arguments = !con(commonArgs, iofArg); 65 66 string mlirBuilder = [{ 67 auto op = $_builder.create<$_qualCppClassName>($_location, $lhs, $rhs); 68 moduleImport.setIntegerOverflowFlags(inst, op); 69 $res = op; 70 }]; 71 let assemblyFormat = [{ 72 $lhs `,` $rhs `` custom<OverflowFlags>($overflowFlags) attr-dict `:` type($res) 73 }]; 74 string llvmBuilder = 75 "$res = builder.Create" # instName # 76 "($lhs, $rhs, /*Name=*/\"\", op.hasNoUnsignedWrap(), op.hasNoSignedWrap());"; 77} 78class LLVM_IntArithmeticOpWithExactFlag<string mnemonic, string instName, 79 list<Trait> traits = []> : 80 LLVM_ArithmeticOpBase<AnySignlessInteger, mnemonic, instName, 81 !listconcat([DeclareOpInterfaceMethods<ExactFlagInterface>], traits)> { 82 let arguments = !con(commonArgs, (ins UnitAttr:$isExact)); 83 84 string mlirBuilder = [{ 85 auto op = $_builder.create<$_qualCppClassName>($_location, $lhs, $rhs); 86 moduleImport.setExactFlag(inst, op); 87 $res = op; 88 }]; 89 let assemblyFormat = [{ 90 (`exact` $isExact^)? $lhs `,` $rhs attr-dict `:` type($res) 91 }]; 92 string llvmBuilder = 93 "$res = builder.Create" # instName # 94 "($lhs, $rhs, /*Name=*/\"\", op.getIsExact());"; 95} 96class LLVM_IntArithmeticOpWithDisjointFlag<string mnemonic, string instName, 97 list<Trait> traits = []> : 98 LLVM_ArithmeticOpBase<AnySignlessInteger, mnemonic, instName, 99 !listconcat([DeclareOpInterfaceMethods<DisjointFlagInterface>], traits)> { 100 let arguments = !con(commonArgs, (ins UnitAttr:$isDisjoint)); 101 102 string mlirBuilder = [{ 103 auto op = $_builder.create<$_qualCppClassName>($_location, $lhs, $rhs); 104 moduleImport.setDisjointFlag(inst, op); 105 $res = op; 106 }]; 107 let assemblyFormat = [{ 108 (`disjoint` $isDisjoint^)? $lhs `,` $rhs attr-dict `:` type($res) 109 }]; 110 string llvmBuilder = [{ 111 auto inst = builder.Create}] # instName # [{($lhs, $rhs, /*Name=*/""); 112 moduleTranslation.setDisjointFlag(op, inst); 113 $res = inst; 114 }]; 115} 116class LLVM_FloatArithmeticOp<string mnemonic, string instName, 117 list<Trait> traits = []> : 118 LLVM_ArithmeticOpBase<LLVM_AnyFloat, mnemonic, instName, 119 !listconcat([DeclareOpInterfaceMethods<FastmathFlagsInterface>], traits)> { 120 dag fmfArg = ( 121 ins DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags); 122 let arguments = !con(commonArgs, fmfArg); 123 string mlirBuilder = [{ 124 auto op = $_builder.create<$_qualCppClassName>($_location, $lhs, $rhs); 125 moduleImport.setFastmathFlagsAttr(inst, op); 126 $res = op; 127 }]; 128} 129 130// Class for arithmetic unary operations. 131class LLVM_UnaryFloatArithmeticOp<Type type, string mnemonic, 132 string instName, list<Trait> traits = []> : 133 LLVM_Op<mnemonic, 134 !listconcat([Pure, SameOperandsAndResultType, DeclareOpInterfaceMethods<FastmathFlagsInterface>], traits)>, 135 LLVM_Builder<"$res = builder.Create" # instName # "($operand);"> { 136 let arguments = ( 137 ins type:$operand, 138 DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags); 139 let results = (outs type:$res); 140 let builders = [LLVM_OneResultOpBuilder]; 141 let assemblyFormat = "$operand attr-dict `:` type($res)"; 142 string llvmInstName = instName; 143 string mlirBuilder = [{ 144 auto op = $_builder.create<$_qualCppClassName>($_location, $operand); 145 moduleImport.setFastmathFlagsAttr(inst, op); 146 $res = op; 147 }]; 148} 149 150// Integer binary operations. 151def LLVM_AddOp : LLVM_IntArithmeticOpWithOverflowFlag<"add", "Add", 152 [Commutative]>; 153def LLVM_SubOp : LLVM_IntArithmeticOpWithOverflowFlag<"sub", "Sub", []>; 154def LLVM_MulOp : LLVM_IntArithmeticOpWithOverflowFlag<"mul", "Mul", 155 [Commutative]>; 156def LLVM_UDivOp : LLVM_IntArithmeticOpWithExactFlag<"udiv", "UDiv">; 157def LLVM_SDivOp : LLVM_IntArithmeticOpWithExactFlag<"sdiv", "SDiv">; 158def LLVM_URemOp : LLVM_IntArithmeticOp<"urem", "URem">; 159def LLVM_SRemOp : LLVM_IntArithmeticOp<"srem", "SRem">; 160def LLVM_AndOp : LLVM_IntArithmeticOp<"and", "And">; 161def LLVM_OrOp : LLVM_IntArithmeticOpWithDisjointFlag<"or", "Or"> { 162 let hasFolder = 1; 163} 164def LLVM_XOrOp : LLVM_IntArithmeticOp<"xor", "Xor">; 165def LLVM_ShlOp : LLVM_IntArithmeticOpWithOverflowFlag<"shl", "Shl", []> { 166 let hasFolder = 1; 167} 168def LLVM_LShrOp : LLVM_IntArithmeticOpWithExactFlag<"lshr", "LShr">; 169def LLVM_AShrOp : LLVM_IntArithmeticOpWithExactFlag<"ashr", "AShr">; 170 171// Base class for compare operations. A compare operation takes two operands 172// of the same type and returns a boolean result. If the operands are 173// vectors, then the result has to be a boolean vector of the same shape. 174class LLVM_ArithmeticCmpOp<string mnemonic, list<Trait> traits = []> : 175 LLVM_Op<mnemonic, traits # [SameTypeOperands, TypesMatchWith< 176 "result type has i1 element type and same shape as operands", 177 "lhs", "res", "::getI1SameShape($_self)">]> { 178 let results = (outs LLVM_ScalarOrVectorOf<I1>:$res); 179} 180 181// Other integer operations. 182def LLVM_ICmpOp : LLVM_ArithmeticCmpOp<"icmp", [Pure]> { 183 let arguments = (ins ICmpPredicate:$predicate, 184 AnyTypeOf<[LLVM_ScalarOrVectorOf<AnySignlessInteger>, 185 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>]>:$lhs, 186 AnyTypeOf<[LLVM_ScalarOrVectorOf<AnySignlessInteger>, 187 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>]>:$rhs); 188 let hasCustomAssemblyFormat = 1; 189 string llvmInstName = "ICmp"; 190 string llvmBuilder = [{ 191 $res = builder.CreateICmp( 192 convertICmpPredicateToLLVM($predicate), $lhs, $rhs); 193 }]; 194 string mlirBuilder = [{ 195 auto *iCmpInst = cast<llvm::ICmpInst>(inst); 196 $res = $_builder.create<$_qualCppClassName>($_location, 197 convertICmpPredicateFromLLVM(iCmpInst->getPredicate()), $lhs, $rhs); 198 }]; 199 // Set the $predicate index to -1 to indicate there is no matching operand 200 // and decrement the following indices. 201 list<int> llvmArgIndices = [-1, 0, 1]; 202 let hasFolder = 1; 203} 204 205// Other floating-point operations. 206def LLVM_FCmpOp : LLVM_ArithmeticCmpOp<"fcmp", [ 207 Pure, DeclareOpInterfaceMethods<FastmathFlagsInterface>]> { 208 let arguments = (ins FCmpPredicate:$predicate, 209 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$lhs, 210 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$rhs, 211 DefaultValuedAttr<LLVM_FastmathFlagsAttr, 212 "{}">:$fastmathFlags); 213 let hasCustomAssemblyFormat = 1; 214 string llvmInstName = "FCmp"; 215 string llvmBuilder = [{ 216 $res = builder.CreateFCmp(convertFCmpPredicateToLLVM($predicate), $lhs, $rhs); 217 }]; 218 string mlirBuilder = [{ 219 auto *fCmpInst = cast<llvm::FCmpInst>(inst); 220 auto op = $_builder.create<$_qualCppClassName>( 221 $_location, convertFCmpPredicateFromLLVM(fCmpInst->getPredicate()), $lhs, $rhs); 222 moduleImport.setFastmathFlagsAttr(inst, op); 223 $res = op; 224 }]; 225 // Set the $predicate index to -1 to indicate there is no matching operand 226 // and decrement the following indices. 227 list<int> llvmArgIndices = [-1, 0, 1, 2]; 228} 229 230// Floating point binary operations. 231def LLVM_FAddOp : LLVM_FloatArithmeticOp<"fadd", "FAdd">; 232def LLVM_FSubOp : LLVM_FloatArithmeticOp<"fsub", "FSub">; 233def LLVM_FMulOp : LLVM_FloatArithmeticOp<"fmul", "FMul">; 234def LLVM_FDivOp : LLVM_FloatArithmeticOp<"fdiv", "FDiv">; 235def LLVM_FRemOp : LLVM_FloatArithmeticOp<"frem", "FRem">; 236def LLVM_FNegOp : LLVM_UnaryFloatArithmeticOp< 237 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, "fneg", "FNeg">; 238 239// Memory-related operations. 240def LLVM_AllocaOp : LLVM_Op<"alloca", 241 [DeclareOpInterfaceMethods<PromotableAllocationOpInterface>, 242 DeclareOpInterfaceMethods<DestructurableAllocationOpInterface>]>, 243 LLVM_MemOpPatterns { 244 let arguments = (ins AnySignlessInteger:$arraySize, 245 OptionalAttr<I64Attr>:$alignment, 246 TypeAttr:$elem_type, 247 UnitAttr:$inalloca); 248 let results = (outs Res<LLVM_AnyPointer, "", 249 [MemAlloc<AutomaticAllocationScopeResource>]>:$res); 250 string llvmInstName = "Alloca"; 251 string llvmBuilder = [{ 252 auto addrSpace = $_resultType->getPointerAddressSpace(); 253 llvm::Type *elementType = moduleTranslation.convertType($elem_type); 254 auto *inst = builder.CreateAlloca(elementType, addrSpace, $arraySize); 255 }] # setAlignmentCode # [{ 256 inst->setUsedWithInAlloca($inalloca); 257 $res = inst; 258 }]; 259 string mlirBuilder = [{ 260 auto *allocaInst = cast<llvm::AllocaInst>(inst); 261 Type allocatedType = 262 moduleImport.convertType(allocaInst->getAllocatedType()); 263 unsigned alignment = allocaInst->getAlign().value(); 264 $res = $_builder.create<LLVM::AllocaOp>( 265 $_location, $_resultType, $arraySize, 266 alignment == 0 ? IntegerAttr() : $_builder.getI64IntegerAttr(alignment), 267 allocatedType, allocaInst->isUsedWithInAlloca()); 268 }]; 269 let builders = [ 270 OpBuilder<(ins "Type":$resultType, "Type":$elementType, "Value":$arraySize, 271 CArg<"unsigned", "0">:$alignment), 272 [{ 273 build($_builder, $_state, resultType, arraySize, 274 alignment == 0 ? IntegerAttr() 275 : $_builder.getI64IntegerAttr(alignment), 276 elementType, false); 277 278 }]> 279 ]; 280 let hasCustomAssemblyFormat = 1; 281 let hasVerifier = 1; 282} 283 284def LLVM_GEPOp : LLVM_Op<"getelementptr", [Pure, 285 DeclareOpInterfaceMethods<PromotableOpInterface>, 286 DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>, 287 DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>, 288 DeclareOpInterfaceMethods<ViewLikeOpInterface> 289 ]> { 290 let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_AnyPointer>:$base, 291 Variadic<LLVM_ScalarOrVectorOf<AnySignlessInteger>>:$dynamicIndices, 292 DenseI32ArrayAttr:$rawConstantIndices, 293 TypeAttr:$elem_type, 294 UnitAttr:$inbounds); 295 let results = (outs LLVM_ScalarOrVectorOf<LLVM_AnyPointer>:$res); 296 let skipDefaultBuilders = 1; 297 298 let description = [{ 299 This operation mirrors LLVM IRs 'getelementptr' operation that is used to 300 perform pointer arithmetic. 301 302 Like in LLVM IR, it is possible to use both constants as well as SSA values 303 as indices. In the case of indexing within a structure, it is required to 304 either use constant indices directly, or supply a constant SSA value. 305 306 An optional 'inbounds' attribute specifies the low-level pointer arithmetic 307 overflow behavior that LLVM uses after lowering the operation to LLVM IR. 308 309 Examples: 310 311 ```mlir 312 // GEP with an SSA value offset 313 %0 = llvm.getelementptr %1[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32 314 315 // GEP with a constant offset and the inbounds attribute set 316 %0 = llvm.getelementptr inbounds %1[3] : (!llvm.ptr) -> !llvm.ptr, f32 317 318 // GEP with constant offsets into a structure 319 %0 = llvm.getelementptr %1[0, 1] 320 : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, f32)> 321 ``` 322 }]; 323 324 let builders = [ 325 OpBuilder<(ins "Type":$resultType, "Type":$elementType, "Value":$basePtr, 326 "ValueRange":$indices, CArg<"bool", "false">:$inbounds, 327 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, 328 OpBuilder<(ins "Type":$resultType, "Type":$elementType, "Value":$basePtr, 329 "ArrayRef<GEPArg>":$indices, CArg<"bool", "false">:$inbounds, 330 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, 331 ]; 332 let llvmBuilder = [{ 333 SmallVector<llvm::Value *> indices; 334 indices.reserve($rawConstantIndices.size()); 335 GEPIndicesAdaptor<decltype($dynamicIndices)> 336 gepIndices(op.getRawConstantIndicesAttr(), $dynamicIndices); 337 for (PointerUnion<IntegerAttr, llvm::Value*> valueOrAttr : gepIndices) { 338 if (llvm::Value* value = ::llvm::dyn_cast<llvm::Value*>(valueOrAttr)) 339 indices.push_back(value); 340 else 341 indices.push_back( 342 builder.getInt32(cast<IntegerAttr>(valueOrAttr).getInt())); 343 } 344 Type baseElementType = op.getElemType(); 345 llvm::Type *elementType = moduleTranslation.convertType(baseElementType); 346 $res = builder.CreateGEP(elementType, $base, indices, "", $inbounds); 347 }]; 348 let assemblyFormat = [{ 349 (`inbounds` $inbounds^)? 350 $base `[` custom<GEPIndices>($dynamicIndices, $rawConstantIndices) `]` attr-dict 351 `:` functional-type(operands, results) `,` $elem_type 352 }]; 353 354 let extraClassDeclaration = [{ 355 constexpr static int32_t kDynamicIndex = std::numeric_limits<int32_t>::min(); 356 357 GEPIndicesAdaptor<ValueRange> getIndices(); 358 }]; 359 let hasFolder = 1; 360 let hasVerifier = 1; 361} 362 363def LLVM_LoadOp : LLVM_MemAccessOpBase<"load", 364 [DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>, 365 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>, 366 DeclareOpInterfaceMethods<PromotableMemOpInterface>, 367 DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>]> { 368 dag args = (ins LLVM_AnyPointer:$addr, 369 OptionalAttr<I64Attr>:$alignment, 370 UnitAttr:$volatile_, 371 UnitAttr:$nontemporal, 372 UnitAttr:$invariant, 373 UnitAttr:$invariantGroup, 374 DefaultValuedAttr< 375 AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering, 376 OptionalAttr<StrAttr>:$syncscope); 377 // Append the aliasing related attributes defined in LLVM_MemAccessOpBase. 378 let arguments = !con(args, aliasAttrs); 379 let results = (outs LLVM_LoadableType:$res); 380 string llvmInstName = "Load"; 381 let description = [{ 382 The `load` operation is used to read from memory. A load may be marked as 383 atomic, volatile, and/or nontemporal, and takes a number of optional 384 attributes that specify aliasing information. 385 386 An atomic load only supports a limited set of pointer, integer, and 387 floating point types, and requires an explicit alignment. 388 389 Examples: 390 ```mlir 391 // A volatile load of a float variable. 392 %0 = llvm.load volatile %ptr : !llvm.ptr -> f32 393 394 // A nontemporal load of a float variable. 395 %0 = llvm.load %ptr {nontemporal} : !llvm.ptr -> f32 396 397 // An atomic load of an integer variable. 398 %0 = llvm.load %ptr atomic monotonic {alignment = 8 : i64} 399 : !llvm.ptr -> i64 400 ``` 401 402 See the following link for more details: 403 https://llvm.org/docs/LangRef.html#load-instruction 404 }]; 405 let assemblyFormat = [{ 406 (`volatile` $volatile_^)? $addr 407 (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)? 408 (`invariant` $invariant^)? 409 (`invariant_group` $invariantGroup^)? 410 attr-dict `:` qualified(type($addr)) `->` type($res) 411 }]; 412 string llvmBuilder = [{ 413 auto *inst = builder.CreateLoad($_resultType, $addr, $volatile_); 414 $res = inst; 415 if ($invariant) { 416 llvm::MDNode *metadata = llvm::MDNode::get(inst->getContext(), std::nullopt); 417 inst->setMetadata(llvm::LLVMContext::MD_invariant_load, metadata); 418 } 419 }] # setOrderingCode 420 # setSyncScopeCode 421 # setAlignmentCode 422 # setNonTemporalMetadataCode 423 # setInvariantGroupCode 424 # setAccessGroupsMetadataCode 425 # setAliasAnalysisMetadataCode; 426 string mlirBuilder = [{ 427 auto *loadInst = cast<llvm::LoadInst>(inst); 428 unsigned alignment = loadInst->getAlign().value(); 429 $res = $_builder.create<LLVM::LoadOp>($_location, $_resultType, $addr, 430 alignment, loadInst->isVolatile(), 431 loadInst->hasMetadata(llvm::LLVMContext::MD_nontemporal), 432 loadInst->hasMetadata(llvm::LLVMContext::MD_invariant_load), 433 loadInst->hasMetadata(llvm::LLVMContext::MD_invariant_group), 434 convertAtomicOrderingFromLLVM(loadInst->getOrdering()), 435 getLLVMSyncScope(loadInst)); 436 }]; 437 let builders = [ 438 OpBuilder<(ins "Type":$type, "Value":$addr, 439 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile, 440 CArg<"bool", "false">:$isNonTemporal, CArg<"bool", "false">:$isInvariant, 441 CArg<"bool", "false">:$isInvariantGroup, 442 CArg<"AtomicOrdering", "AtomicOrdering::not_atomic">:$ordering, 443 CArg<"StringRef", "StringRef()">:$syncscope)> 444 ]; 445 let hasVerifier = 1; 446} 447 448def LLVM_StoreOp : LLVM_MemAccessOpBase<"store", 449 [DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>, 450 DeclareOpInterfaceMethods<MemoryEffectsOpInterface>, 451 DeclareOpInterfaceMethods<PromotableMemOpInterface>, 452 DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>]> { 453 dag args = (ins LLVM_LoadableType:$value, 454 LLVM_AnyPointer:$addr, 455 OptionalAttr<I64Attr>:$alignment, 456 UnitAttr:$volatile_, 457 UnitAttr:$nontemporal, 458 UnitAttr:$invariantGroup, 459 DefaultValuedAttr< 460 AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering, 461 OptionalAttr<StrAttr>:$syncscope); 462 // Append the aliasing related attributes defined in LLVM_MemAccessOpBase. 463 let arguments = !con(args, aliasAttrs); 464 string llvmInstName = "Store"; 465 let description = [{ 466 The `store` operation is used to write to memory. A store may be marked as 467 atomic, volatile, and/or nontemporal, and takes a number of optional 468 attributes that specify aliasing information. 469 470 An atomic store only supports a limited set of pointer, integer, and 471 floating point types, and requires an explicit alignment. 472 473 Examples: 474 ```mlir 475 // A volatile store of a float variable. 476 llvm.store volatile %val, %ptr : f32, !llvm.ptr 477 478 // A nontemporal store of a float variable. 479 llvm.store %val, %ptr {nontemporal} : f32, !llvm.ptr 480 481 // An atomic store of an integer variable. 482 llvm.store %val, %ptr atomic monotonic {alignment = 8 : i64} 483 : i64, !llvm.ptr 484 ``` 485 486 See the following link for more details: 487 https://llvm.org/docs/LangRef.html#store-instruction 488 }]; 489 let assemblyFormat = [{ 490 (`volatile` $volatile_^)? $value `,` $addr 491 (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)? 492 (`invariant_group` $invariantGroup^)? 493 attr-dict `:` type($value) `,` qualified(type($addr)) 494 }]; 495 string llvmBuilder = [{ 496 auto *inst = builder.CreateStore($value, $addr, $volatile_); 497 }] # setOrderingCode 498 # setSyncScopeCode 499 # setAlignmentCode 500 # setNonTemporalMetadataCode 501 # setInvariantGroupCode 502 # setAccessGroupsMetadataCode 503 # setAliasAnalysisMetadataCode; 504 string mlirBuilder = [{ 505 auto *storeInst = cast<llvm::StoreInst>(inst); 506 unsigned alignment = storeInst->getAlign().value(); 507 $_op = $_builder.create<LLVM::StoreOp>($_location, $value, $addr, 508 alignment, storeInst->isVolatile(), 509 storeInst->hasMetadata(llvm::LLVMContext::MD_nontemporal), 510 storeInst->hasMetadata(llvm::LLVMContext::MD_invariant_group), 511 convertAtomicOrderingFromLLVM(storeInst->getOrdering()), 512 getLLVMSyncScope(storeInst)); 513 }]; 514 let builders = [ 515 OpBuilder<(ins "Value":$value, "Value":$addr, 516 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile, 517 CArg<"bool", "false">:$isNonTemporal, 518 CArg<"bool", "false">:$isInvariantGroup, 519 CArg<"AtomicOrdering", "AtomicOrdering::not_atomic">:$ordering, 520 CArg<"StringRef", "StringRef()">:$syncscope)> 521 ]; 522 let hasVerifier = 1; 523} 524 525// Casts. 526class LLVM_CastOp<string mnemonic, string instName, Type type, 527 Type resultType, list<Trait> traits = []> : 528 LLVM_Op<mnemonic, !listconcat([Pure], traits)>, 529 LLVM_Builder<"$res = builder.Create" # instName # "($arg, $_resultType);"> { 530 let arguments = (ins type:$arg); 531 let results = (outs resultType:$res); 532 let builders = [LLVM_OneResultOpBuilder]; 533 let assemblyFormat = "$arg attr-dict `:` type($arg) `to` type($res)"; 534 string llvmInstName = instName; 535 string mlirBuilder = [{ 536 $res = $_builder.create<$_qualCppClassName>( 537 $_location, $_resultType, $arg); 538 }]; 539} 540class LLVM_CastOpWithNNegFlag<string mnemonic, string instName, Type type, 541 Type resultType, list<Trait> traits = []> : 542 LLVM_Op<mnemonic, !listconcat([Pure], [DeclareOpInterfaceMethods<NonNegFlagInterface>], traits)>, 543 LLVM_Builder<"$res = builder.Create" # instName # "($arg, $_resultType, /*Name=*/\"\", op.getNonNeg());"> { 544 let arguments = (ins type:$arg, UnitAttr:$nonNeg); 545 let results = (outs resultType:$res); 546 let builders = [LLVM_OneResultOpBuilder]; 547 let assemblyFormat = "(`nneg` $nonNeg^)? $arg attr-dict `:` type($arg) `to` type($res)"; 548 string llvmInstName = instName; 549 string mlirBuilder = [{ 550 auto op = $_builder.create<$_qualCppClassName>( 551 $_location, $_resultType, $arg); 552 moduleImport.setNonNegFlag(inst, op); 553 $res = op; 554 }]; 555} 556 557class LLVM_CastOpWithOverflowFlag<string mnemonic, string instName, Type type, 558 Type resultType, list<Trait> traits = []> : 559 LLVM_Op<mnemonic, !listconcat([Pure], [DeclareOpInterfaceMethods<IntegerOverflowFlagsInterface>], traits)>, 560 LLVM_Builder<"$res = builder.Create" # instName # "($arg, $_resultType, /*Name=*/\"\", op.hasNoUnsignedWrap(), op.hasNoSignedWrap());"> { 561 let arguments = (ins type:$arg, EnumProp<"IntegerOverflowFlags", "", "IntegerOverflowFlags::none">:$overflowFlags); 562 let results = (outs resultType:$res); 563 let builders = [LLVM_OneResultOpBuilder]; 564 let assemblyFormat = "$arg `` custom<OverflowFlags>($overflowFlags) attr-dict `:` type($arg) `to` type($res)"; 565 string llvmInstName = instName; 566 string mlirBuilder = [{ 567 auto op = $_builder.create<$_qualCppClassName>( 568 $_location, $_resultType, $arg); 569 moduleImport.setIntegerOverflowFlags(inst, op); 570 $res = op; 571 }]; 572} 573 574def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "BitCast", LLVM_AnyNonAggregate, 575 LLVM_AnyNonAggregate, [DeclareOpInterfaceMethods<PromotableOpInterface>]> { 576 let hasFolder = 1; 577 let hasVerifier = 1; 578} 579def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "AddrSpaceCast", 580 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>, 581 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>, 582 [DeclareOpInterfaceMethods<PromotableOpInterface>, 583 DeclareOpInterfaceMethods<ViewLikeOpInterface>]> { 584 let hasFolder = 1; 585} 586def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "IntToPtr", 587 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 588 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>; 589def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "PtrToInt", 590 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>, 591 LLVM_ScalarOrVectorOf<AnySignlessInteger>>; 592def LLVM_SExtOp : LLVM_CastOp<"sext", "SExt", 593 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 594 LLVM_ScalarOrVectorOf<AnySignlessInteger>> { 595 let hasVerifier = 1; 596} 597def LLVM_ZExtOp : LLVM_CastOpWithNNegFlag<"zext", "ZExt", 598 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 599 LLVM_ScalarOrVectorOf<AnySignlessInteger>> { 600 let hasFolder = 1; 601 let hasVerifier = 1; 602} 603def LLVM_TruncOp : LLVM_CastOpWithOverflowFlag<"trunc", "Trunc", 604 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 605 LLVM_ScalarOrVectorOf<AnySignlessInteger>>; 606def LLVM_SIToFPOp : LLVM_CastOp<"sitofp", "SIToFP", 607 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 608 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 609def LLVM_UIToFPOp : LLVM_CastOpWithNNegFlag<"uitofp", "UIToFP", 610 LLVM_ScalarOrVectorOf<AnySignlessInteger>, 611 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 612def LLVM_FPToSIOp : LLVM_CastOp<"fptosi", "FPToSI", 613 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 614 LLVM_ScalarOrVectorOf<AnySignlessInteger>>; 615def LLVM_FPToUIOp : LLVM_CastOp<"fptoui", "FPToUI", 616 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 617 LLVM_ScalarOrVectorOf<AnySignlessInteger>>; 618def LLVM_FPExtOp : LLVM_CastOp<"fpext", "FPExt", 619 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 620 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 621def LLVM_FPTruncOp : LLVM_CastOp<"fptrunc", "FPTrunc", 622 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 623 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 624 625// Call-related operations. 626def LLVM_InvokeOp : LLVM_Op<"invoke", [ 627 AttrSizedOperandSegments, 628 DeclareOpInterfaceMethods<BranchOpInterface>, 629 DeclareOpInterfaceMethods<CallOpInterface>, 630 DeclareOpInterfaceMethods<BranchWeightOpInterface>, 631 Terminator]> { 632 let arguments = (ins 633 OptionalAttr<TypeAttrOf<LLVM_FunctionType>>:$var_callee_type, 634 OptionalAttr<FlatSymbolRefAttr>:$callee, 635 Variadic<LLVM_Type>:$callee_operands, 636 Variadic<LLVM_Type>:$normalDestOperands, 637 Variadic<LLVM_Type>:$unwindDestOperands, 638 OptionalAttr<DenseI32ArrayAttr>:$branch_weights, 639 DefaultValuedAttr<CConv, "CConv::C">:$CConv, 640 VariadicOfVariadic<LLVM_Type, 641 "op_bundle_sizes">:$op_bundle_operands, 642 DenseI32ArrayAttr:$op_bundle_sizes, 643 OptionalAttr<ArrayAttr>:$op_bundle_tags); 644 let results = (outs Optional<LLVM_Type>:$result); 645 let successors = (successor AnySuccessor:$normalDest, 646 AnySuccessor:$unwindDest); 647 648 let builders = [ 649 OpBuilder<(ins "LLVMFuncOp":$func, 650 "ValueRange":$ops, "Block*":$normal, "ValueRange":$normalOps, 651 "Block*":$unwind, "ValueRange":$unwindOps)>, 652 OpBuilder<(ins "TypeRange":$tys, "FlatSymbolRefAttr":$callee, 653 "ValueRange":$ops, "Block*":$normal, "ValueRange":$normalOps, 654 "Block*":$unwind, "ValueRange":$unwindOps)>, 655 OpBuilder<(ins "LLVMFunctionType":$calleeType, "FlatSymbolRefAttr":$callee, 656 "ValueRange":$ops, "Block*":$normal, "ValueRange":$normalOps, 657 "Block*":$unwind, "ValueRange":$unwindOps)>]; 658 let hasCustomAssemblyFormat = 1; 659 let hasVerifier = 1; 660 let extraClassDeclaration = [{ 661 /// Returns the callee function type. 662 LLVMFunctionType getCalleeFunctionType(); 663 }]; 664} 665 666def LLVM_LandingpadOp : LLVM_Op<"landingpad"> { 667 let arguments = (ins UnitAttr:$cleanup, Variadic<LLVM_Type>); 668 let results = (outs LLVM_Type:$res); 669 let builders = [LLVM_OneResultOpBuilder]; 670 let hasCustomAssemblyFormat = 1; 671 let hasVerifier = 1; 672} 673 674//===----------------------------------------------------------------------===// 675// VAArgOp 676//===----------------------------------------------------------------------===// 677 678def LLVM_VaArgOp : LLVM_Op<"va_arg"> { 679 let arguments = (ins LLVM_AnyPointer:$arg); 680 let results = (outs LLVM_Type:$res); 681 682 let builders = [LLVM_OneResultOpBuilder]; 683 684 let llvmBuilder = " $res = builder.CreateVAArg($arg, $_resultType); "; 685 let assemblyFormat = "$arg attr-dict `:` functional-type($arg, $res)"; 686 687 string llvmInstName = "VAArg"; 688 string mlirBuilder = [{ 689 $res = $_builder.create<mlir::LLVM::VaArgOp>( 690 $_location, $_resultType, $arg); 691 }]; 692} 693 694//===----------------------------------------------------------------------===// 695// CallOp 696//===----------------------------------------------------------------------===// 697 698def LLVM_CallOp : LLVM_MemAccessOpBase<"call", 699 [AttrSizedOperandSegments, 700 DeclareOpInterfaceMethods<FastmathFlagsInterface>, 701 DeclareOpInterfaceMethods<CallOpInterface>, 702 DeclareOpInterfaceMethods<SymbolUserOpInterface>, 703 DeclareOpInterfaceMethods<BranchWeightOpInterface>]> { 704 let summary = "Call to an LLVM function."; 705 let description = [{ 706 In LLVM IR, functions may return either 0 or 1 value. LLVM IR dialect 707 implements this behavior by providing a variadic `call` operation for 0- and 708 1-result functions. Even though MLIR supports multi-result functions, LLVM 709 IR dialect disallows them. 710 711 The `call` instruction supports both direct and indirect calls. Direct calls 712 start with a function name (`@`-prefixed) and indirect calls start with an 713 SSA value (`%`-prefixed). The direct callee, if present, is stored as a 714 function attribute `callee`. For indirect calls, the callee is of `!llvm.ptr` type 715 and is stored as the first value in `callee_operands`. If and only if the 716 callee is a variadic function, the `var_callee_type` attribute must carry 717 the variadic LLVM function type. The trailing type list contains the 718 optional indirect callee type and the MLIR function type, which differs from 719 the LLVM function type that uses an explicit void type to model functions 720 that do not return a value. 721 722 Examples: 723 724 ```mlir 725 // Direct call without arguments and with one result. 726 %0 = llvm.call @foo() : () -> (f32) 727 728 // Direct call with arguments and without a result. 729 llvm.call @bar(%0) : (f32) -> () 730 731 // Indirect call with an argument and without a result. 732 %1 = llvm.mlir.addressof @foo : !llvm.ptr 733 llvm.call %1(%0) : !llvm.ptr, (f32) -> () 734 735 // Direct variadic call. 736 llvm.call @printf(%0, %1) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i32) -> i32 737 738 // Indirect variadic call 739 llvm.call %1(%0) vararg(!llvm.func<void (...)>) : !llvm.ptr, (i32) -> () 740 ``` 741 }]; 742 743 dag args = (ins OptionalAttr<TypeAttrOf<LLVM_FunctionType>>:$var_callee_type, 744 OptionalAttr<FlatSymbolRefAttr>:$callee, 745 Variadic<LLVM_Type>:$callee_operands, 746 DefaultValuedAttr<LLVM_FastmathFlagsAttr, 747 "{}">:$fastmathFlags, 748 OptionalAttr<DenseI32ArrayAttr>:$branch_weights, 749 DefaultValuedAttr<CConv, "CConv::C">:$CConv, 750 DefaultValuedAttr<TailCallKind, "TailCallKind::None">:$TailCallKind, 751 OptionalAttr<LLVM_MemoryEffectsAttr>:$memory_effects, 752 OptionalAttr<UnitAttr>:$convergent, 753 OptionalAttr<UnitAttr>:$no_unwind, 754 OptionalAttr<UnitAttr>:$will_return, 755 VariadicOfVariadic<LLVM_Type, 756 "op_bundle_sizes">:$op_bundle_operands, 757 DenseI32ArrayAttr:$op_bundle_sizes, 758 OptionalAttr<ArrayAttr>:$op_bundle_tags); 759 // Append the aliasing related attributes defined in LLVM_MemAccessOpBase. 760 let arguments = !con(args, aliasAttrs); 761 let results = (outs Optional<LLVM_Type>:$result); 762 let builders = [ 763 OpBuilder<(ins "LLVMFuncOp":$func, "ValueRange":$args)>, 764 OpBuilder<(ins "LLVMFunctionType":$calleeType, "ValueRange":$args)>, 765 OpBuilder<(ins "TypeRange":$results, "StringAttr":$callee, 766 CArg<"ValueRange", "{}">:$args)>, 767 OpBuilder<(ins "TypeRange":$results, "FlatSymbolRefAttr":$callee, 768 CArg<"ValueRange", "{}">:$args)>, 769 OpBuilder<(ins "TypeRange":$results, "StringRef":$callee, 770 CArg<"ValueRange", "{}">:$args)>, 771 OpBuilder<(ins "LLVMFunctionType":$calleeType, "StringAttr":$callee, 772 CArg<"ValueRange", "{}">:$args)>, 773 OpBuilder<(ins "LLVMFunctionType":$calleeType, "FlatSymbolRefAttr":$callee, 774 CArg<"ValueRange", "{}">:$args)>, 775 OpBuilder<(ins "LLVMFunctionType":$calleeType, "StringRef":$callee, 776 CArg<"ValueRange", "{}">:$args)> 777 ]; 778 let hasVerifier = 1; 779 let hasCustomAssemblyFormat = 1; 780 let extraClassDeclaration = [{ 781 /// Returns the callee function type. 782 LLVMFunctionType getCalleeFunctionType(); 783 }]; 784} 785 786//===----------------------------------------------------------------------===// 787// ExtractElementOp 788//===----------------------------------------------------------------------===// 789 790def LLVM_ExtractElementOp : LLVM_Op<"extractelement", [Pure, 791 TypesMatchWith<"result type matches vector element type", "vector", "res", 792 "LLVM::getVectorElementType($_self)">]> { 793 let summary = "Extract an element from an LLVM vector."; 794 795 let arguments = (ins LLVM_AnyVector:$vector, AnySignlessInteger:$position); 796 let results = (outs LLVM_Type:$res); 797 798 let assemblyFormat = [{ 799 $vector `[` $position `:` type($position) `]` attr-dict `:` type($vector) 800 }]; 801 802 string llvmInstName = "ExtractElement"; 803 string llvmBuilder = [{ 804 $res = builder.CreateExtractElement($vector, $position); 805 }]; 806 string mlirBuilder = [{ 807 $res = $_builder.create<LLVM::ExtractElementOp>( 808 $_location, $vector, $position); 809 }]; 810} 811 812//===----------------------------------------------------------------------===// 813// ExtractValueOp 814//===----------------------------------------------------------------------===// 815 816def LLVM_ExtractValueOp : LLVM_Op<"extractvalue", [Pure]> { 817 let summary = "Extract a value from an LLVM struct."; 818 819 let arguments = (ins LLVM_AnyAggregate:$container, DenseI64ArrayAttr:$position); 820 let results = (outs LLVM_Type:$res); 821 822 let builders = [ 823 OpBuilder<(ins "Value":$container, "ArrayRef<int64_t>":$position)> 824 ]; 825 826 let assemblyFormat = [{ 827 $container `` $position attr-dict `:` type($container) 828 custom<InsertExtractValueElementType>(type($res), ref(type($container)), 829 ref($position)) 830 }]; 831 832 let hasFolder = 1; 833 let hasVerifier = 1; 834 835 string llvmInstName = "ExtractValue"; 836 string llvmBuilder = [{ 837 $res = builder.CreateExtractValue($container, extractPosition($position)); 838 }]; 839 string mlirBuilder = [{ 840 auto *evInst = cast<llvm::ExtractValueInst>(inst); 841 $res = $_builder.create<LLVM::ExtractValueOp>($_location, 842 $container, getPositionFromIndices(evInst->getIndices())); 843 }]; 844} 845 846//===----------------------------------------------------------------------===// 847// InsertElementOp 848//===----------------------------------------------------------------------===// 849 850def LLVM_InsertElementOp : LLVM_Op<"insertelement", [Pure, 851 TypesMatchWith<"argument type matches vector element type", "vector", 852 "value", "LLVM::getVectorElementType($_self)">, 853 AllTypesMatch<["res", "vector"]>]> { 854 let summary = "Insert an element into an LLVM vector."; 855 856 let arguments = (ins LLVM_AnyVector:$vector, LLVM_PrimitiveType:$value, 857 AnySignlessInteger:$position); 858 let results = (outs LLVM_AnyVector:$res); 859 860 let builders = [LLVM_OneResultOpBuilder]; 861 862 let assemblyFormat = [{ 863 $value `,` $vector `[` $position `:` type($position) `]` attr-dict `:` 864 type($vector) 865 }]; 866 867 string llvmInstName = "InsertElement"; 868 string llvmBuilder = [{ 869 $res = builder.CreateInsertElement($vector, $value, $position); 870 }]; 871 string mlirBuilder = [{ 872 $res = $_builder.create<LLVM::InsertElementOp>( 873 $_location, $vector, $value, $position); 874 }]; 875} 876 877//===----------------------------------------------------------------------===// 878// InsertValueOp 879//===----------------------------------------------------------------------===// 880 881def LLVM_InsertValueOp : LLVM_Op< 882 "insertvalue", [Pure, AllTypesMatch<["container", "res"]>]> { 883 let summary = "Insert a value into an LLVM struct."; 884 885 let arguments = (ins LLVM_AnyAggregate:$container, LLVM_PrimitiveType:$value, 886 DenseI64ArrayAttr:$position); 887 let results = (outs LLVM_AnyAggregate:$res); 888 889 let assemblyFormat = [{ 890 $value `,` $container `` $position attr-dict `:` type($container) 891 custom<InsertExtractValueElementType>(type($value), ref(type($container)), 892 ref($position)) 893 }]; 894 895 let hasVerifier = 1; 896 897 string llvmInstName = "InsertValue"; 898 string llvmBuilder = [{ 899 $res = builder.CreateInsertValue($container, $value, 900 extractPosition($position)); 901 }]; 902 string mlirBuilder = [{ 903 auto *ivInst = cast<llvm::InsertValueInst>(inst); 904 $res = $_builder.create<LLVM::InsertValueOp>($_location, 905 $container, $value, getPositionFromIndices(ivInst->getIndices())); 906 }]; 907} 908 909//===----------------------------------------------------------------------===// 910// ShuffleVectorOp 911//===----------------------------------------------------------------------===// 912 913def LLVM_ShuffleVectorOp : LLVM_Op<"shufflevector", 914 [Pure, AllTypesMatch<["v1", "v2"]>]> { 915 let summary = "Construct a permutation of two vectors."; 916 917 let arguments = (ins LLVM_AnyVector:$v1, LLVM_AnyVector:$v2, 918 DenseI32ArrayAttr:$mask); 919 let results = (outs LLVM_AnyVector:$res); 920 921 let builders = [ 922 OpBuilder<(ins "Value":$v1, "Value":$v2, "DenseI32ArrayAttr":$mask, 923 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>, 924 OpBuilder<(ins "Value":$v1, "Value":$v2, "ArrayRef<int32_t>":$mask)> 925 ]; 926 927 let assemblyFormat = [{ 928 $v1 `,` $v2 $mask attr-dict `:` type($v1) 929 custom<ShuffleType>(ref(type($v1)), type($res), ref($mask)) 930 }]; 931 932 let hasVerifier = 1; 933 934 string llvmInstName = "ShuffleVector"; 935 string llvmBuilder = [{ 936 $res = builder.CreateShuffleVector($v1, $v2, $mask); 937 }]; 938 string mlirBuilder = [{ 939 auto *svInst = cast<llvm::ShuffleVectorInst>(inst); 940 SmallVector<int32_t> mask(svInst->getShuffleMask()); 941 $res = $_builder.create<LLVM::ShuffleVectorOp>( 942 $_location, $v1, $v2, mask); 943 }]; 944} 945 946// Misc operations. 947def LLVM_SelectOp 948 : LLVM_Op<"select", 949 [Pure, AllTypesMatch<["trueValue", "falseValue", "res"]>, 950 DeclareOpInterfaceMethods<FastmathFlagsInterface>, 951 DeclareOpInterfaceMethods<SelectLikeOpInterface>]>, 952 LLVM_Builder< 953 "$res = builder.CreateSelect($condition, $trueValue, $falseValue);"> { 954 let arguments = (ins LLVM_ScalarOrVectorOf<I1>:$condition, 955 LLVM_Type:$trueValue, LLVM_Type:$falseValue, 956 DefaultValuedAttr<LLVM_FastmathFlagsAttr, 957 "{}">:$fastmathFlags); 958 let results = (outs LLVM_Type:$res); 959 let assemblyFormat = "operands attr-dict `:` type($condition) `,` type($res)"; 960 string llvmInstName = "Select"; 961 string mlirBuilder = [{ 962 auto op = $_builder.create<LLVM::SelectOp>( 963 $_location, $_resultType, $condition, $trueValue, $falseValue); 964 moduleImport.setFastmathFlagsAttr(inst, op); 965 $res = op; 966 }]; 967} 968def LLVM_FreezeOp : LLVM_Op<"freeze", [Pure, SameOperandsAndResultType]> { 969 let arguments = (ins LLVM_Type:$val); 970 let results = (outs LLVM_Type:$res); 971 let builders = [LLVM_OneResultOpBuilder]; 972 let assemblyFormat = "$val attr-dict `:` type($val)"; 973 string llvmInstName = "Freeze"; 974 string llvmBuilder = "$res = builder.CreateFreeze($val);"; 975 string mlirBuilder = [{ 976 $res = $_builder.create<LLVM::FreezeOp>($_location, $val); 977 }]; 978} 979 980// Terminators. 981def LLVM_BrOp : LLVM_TerminatorOp<"br", 982 [DeclareOpInterfaceMethods<BranchOpInterface>, Pure]> { 983 let arguments = (ins 984 Variadic<LLVM_Type>:$destOperands, 985 OptionalAttr<LoopAnnotationAttr>:$loop_annotation 986 ); 987 let successors = (successor AnySuccessor:$dest); 988 let assemblyFormat = [{ 989 $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict 990 }]; 991 let builders = [ 992 OpBuilder<(ins "Block *":$dest), [{ 993 build($_builder, $_state, ValueRange(), dest); 994 }]>, 995 OpBuilder<(ins "ValueRange":$operands, "Block *":$dest), [{ 996 build($_builder, $_state, operands, /*loop_annotation=*/{}, dest); 997 }]>, 998 LLVM_TerminatorPassthroughOpBuilder 999 ]; 1000} 1001def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br", 1002 [AttrSizedOperandSegments, 1003 DeclareOpInterfaceMethods<BranchOpInterface>, 1004 DeclareOpInterfaceMethods<BranchWeightOpInterface>, 1005 Pure]> { 1006 let arguments = (ins I1:$condition, 1007 Variadic<LLVM_Type>:$trueDestOperands, 1008 Variadic<LLVM_Type>:$falseDestOperands, 1009 OptionalAttr<DenseI32ArrayAttr>:$branch_weights, 1010 OptionalAttr<LoopAnnotationAttr>:$loop_annotation); 1011 let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest); 1012 let assemblyFormat = [{ 1013 $condition ( `weights` `(` $branch_weights^ `)` )? `,` 1014 $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,` 1015 $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)? 1016 attr-dict 1017 }]; 1018 1019 let builders = [ 1020 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 1021 "ValueRange":$trueOperands, "Block *":$falseDest, 1022 "ValueRange":$falseOperands, 1023 CArg<"std::optional<std::pair<uint32_t, uint32_t>>", "{}">:$weights)>, 1024 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 1025 "Block *":$falseDest, CArg<"ValueRange", "{}">:$falseOperands), 1026 [{ 1027 build($_builder, $_state, condition, trueDest, ValueRange(), falseDest, 1028 falseOperands); 1029 }]>, 1030 OpBuilder<(ins "Value":$condition, "ValueRange":$trueOperands, "ValueRange":$falseOperands, 1031 "DenseI32ArrayAttr":$branchWeights, "Block *":$trueDest, "Block *":$falseDest), 1032 [{ 1033 build($_builder, $_state, condition, trueOperands, falseOperands, branchWeights, 1034 {}, trueDest, falseDest); 1035 }]>, LLVM_TerminatorPassthroughOpBuilder]; 1036} 1037 1038//===----------------------------------------------------------------------===// 1039// ReturnOp 1040//===----------------------------------------------------------------------===// 1041 1042def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [Pure, ReturnLike]> { 1043 let arguments = (ins Optional<LLVM_Type>:$arg); 1044 let assemblyFormat = "attr-dict ($arg^ `:` type($arg))?"; 1045 1046 let builders = [ 1047 OpBuilder<(ins "ValueRange":$args), [{ 1048 build($_builder, $_state, TypeRange(), args); 1049 }]> 1050 ]; 1051 1052 let hasVerifier = 1; 1053 1054 string llvmInstName = "Ret"; 1055 string llvmBuilder = [{ 1056 if ($_numOperands != 0) 1057 builder.CreateRet($arg); 1058 else 1059 builder.CreateRetVoid(); 1060 }]; 1061 string mlirBuilder = [{ 1062 FailureOr<SmallVector<Value>> mlirOperands = 1063 moduleImport.convertValues(llvmOperands); 1064 if (failed(mlirOperands)) 1065 return failure(); 1066 $_op = $_builder.create<LLVM::ReturnOp>($_location, *mlirOperands); 1067 }]; 1068} 1069 1070def LLVM_ResumeOp : LLVM_TerminatorOp<"resume"> { 1071 let arguments = (ins LLVM_Type:$value); 1072 let assemblyFormat = "$value attr-dict `:` type($value)"; 1073 // Consistency of llvm.resume value types is checked in LLVMFuncOp::verify(). 1074 let hasVerifier = false; 1075 string llvmInstName = "Resume"; 1076 string llvmBuilder = [{ builder.CreateResume($value); }]; 1077 string mlirBuilder = [{ 1078 $_op = $_builder.create<LLVM::ResumeOp>($_location, $value); 1079 }]; 1080} 1081def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable"> { 1082 let assemblyFormat = "attr-dict"; 1083 string llvmInstName = "Unreachable"; 1084 string llvmBuilder = [{ builder.CreateUnreachable(); }]; 1085 string mlirBuilder = [{ 1086 $_op = $_builder.create<LLVM::UnreachableOp>($_location); 1087 }]; 1088} 1089 1090def LLVM_SwitchOp : LLVM_TerminatorOp<"switch", 1091 [AttrSizedOperandSegments, 1092 DeclareOpInterfaceMethods<BranchOpInterface>, 1093 DeclareOpInterfaceMethods<BranchWeightOpInterface>, 1094 Pure]> { 1095 let arguments = (ins 1096 AnySignlessInteger:$value, 1097 Variadic<AnyType>:$defaultOperands, 1098 VariadicOfVariadic<AnyType, "case_operand_segments">:$caseOperands, 1099 OptionalAttr<AnyIntElementsAttr>:$case_values, 1100 DenseI32ArrayAttr:$case_operand_segments, 1101 OptionalAttr<DenseI32ArrayAttr>:$branch_weights 1102 ); 1103 let successors = (successor 1104 AnySuccessor:$defaultDestination, 1105 VariadicSuccessor<AnySuccessor>:$caseDestinations 1106 ); 1107 1108 let assemblyFormat = [{ 1109 $value `:` type($value) `,` 1110 $defaultDestination (`(` $defaultOperands^ `:` type($defaultOperands) `)`)? 1111 custom<SwitchOpCases>(ref(type($value)), $case_values, $caseDestinations, 1112 $caseOperands, type($caseOperands)) 1113 attr-dict 1114 }]; 1115 let hasVerifier = 1; 1116 1117 let builders = [ 1118 OpBuilder<(ins "Value":$value, 1119 "Block *":$defaultDestination, 1120 "ValueRange":$defaultOperands, 1121 CArg<"ArrayRef<APInt>", "{}">:$caseValues, 1122 CArg<"BlockRange", "{}">:$caseDestinations, 1123 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands, 1124 CArg<"ArrayRef<int32_t>", "{}">:$branchWeights)>, 1125 OpBuilder<(ins "Value":$value, 1126 "Block *":$defaultDestination, 1127 "ValueRange":$defaultOperands, 1128 CArg<"ArrayRef<int32_t>", "{}">:$caseValues, 1129 CArg<"BlockRange", "{}">:$caseDestinations, 1130 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands, 1131 CArg<"ArrayRef<int32_t>", "{}">:$branchWeights)>, 1132 OpBuilder<(ins "Value":$value, 1133 "Block *":$defaultDestination, 1134 "ValueRange":$defaultOperands, 1135 CArg<"DenseIntElementsAttr", "{}">:$caseValues, 1136 CArg<"BlockRange", "{}">:$caseDestinations, 1137 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands, 1138 CArg<"ArrayRef<int32_t>", "{}">:$branchWeights)>, 1139 LLVM_TerminatorPassthroughOpBuilder 1140 ]; 1141 1142 let extraClassDeclaration = [{ 1143 /// Return the operands for the case destination block at the given index. 1144 OperandRange getCaseOperands(unsigned index) { 1145 return getCaseOperands()[index]; 1146 } 1147 1148 /// Return a mutable range of operands for the case destination block at the 1149 /// given index. 1150 MutableOperandRange getCaseOperandsMutable(unsigned index) { 1151 return getCaseOperandsMutable()[index]; 1152 } 1153 }]; 1154} 1155 1156//////////////////////////////////////////////////////////////////////////////// 1157// Auxiliary operations (do not appear in LLVM IR but necessary for the dialect 1158// to work correctly). 1159//////////////////////////////////////////////////////////////////////////////// 1160 1161def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof", 1162 [Pure, ConstantLike, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { 1163 let arguments = (ins FlatSymbolRefAttr:$global_name); 1164 let results = (outs LLVM_AnyPointer:$res); 1165 1166 let summary = "Creates a pointer pointing to a global or a function"; 1167 1168 let description = [{ 1169 Creates an SSA value containing a pointer to a global variable or constant 1170 defined by `llvm.mlir.global`. The global value can be defined after its 1171 first referenced. If the global value is a constant, storing into it is not 1172 allowed. 1173 1174 Examples: 1175 1176 ```mlir 1177 func @foo() { 1178 // Get the address of a global variable. 1179 %0 = llvm.mlir.addressof @const : !llvm.ptr 1180 1181 // Use it as a regular pointer. 1182 %1 = llvm.load %0 : !llvm.ptr -> i32 1183 1184 // Get the address of a function. 1185 %2 = llvm.mlir.addressof @foo : !llvm.ptr 1186 1187 // The function address can be used for indirect calls. 1188 llvm.call %2() : !llvm.ptr, () -> () 1189 } 1190 1191 // Define the global. 1192 llvm.mlir.global @const(42 : i32) : i32 1193 ``` 1194 }]; 1195 1196 let builders = [ 1197 OpBuilder<(ins "GlobalOp":$global, 1198 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs), 1199 [{ 1200 build($_builder, $_state, 1201 LLVM::LLVMPointerType::get($_builder.getContext(), global.getAddrSpace()), 1202 global.getSymName()); 1203 $_state.addAttributes(attrs); 1204 }]>, 1205 OpBuilder<(ins "LLVMFuncOp":$func, 1206 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs), 1207 [{ 1208 build($_builder, $_state, 1209 LLVM::LLVMPointerType::get($_builder.getContext()), func.getName()); 1210 $_state.addAttributes(attrs); 1211 }]> 1212 ]; 1213 1214 let extraClassDeclaration = [{ 1215 /// Return the llvm.mlir.global operation that defined the value referenced 1216 /// here. 1217 GlobalOp getGlobal(SymbolTableCollection &symbolTable); 1218 1219 /// Return the llvm.func operation that is referenced here. 1220 LLVMFuncOp getFunction(SymbolTableCollection &symbolTable); 1221 }]; 1222 1223 let assemblyFormat = "$global_name attr-dict `:` qualified(type($res))"; 1224 1225 let hasFolder = 1; 1226} 1227 1228def LLVM_GlobalOp : LLVM_Op<"mlir.global", 1229 [IsolatedFromAbove, SingleBlockImplicitTerminator<"ReturnOp">, Symbol]> { 1230 let arguments = (ins 1231 TypeAttr:$global_type, 1232 UnitAttr:$constant, 1233 StrAttr:$sym_name, 1234 Linkage:$linkage, 1235 UnitAttr:$dso_local, 1236 UnitAttr:$thread_local_, 1237 UnitAttr:$externally_initialized, 1238 OptionalAttr<AnyAttr>:$value, 1239 OptionalAttr<I64Attr>:$alignment, 1240 DefaultValuedAttr<ConfinedAttr<I32Attr, [IntNonNegative]>, "0">:$addr_space, 1241 OptionalAttr<UnnamedAddr>:$unnamed_addr, 1242 OptionalAttr<StrAttr>:$section, 1243 OptionalAttr<SymbolRefAttr>:$comdat, 1244 OptionalAttr<DIGlobalVariableExpressionArrayAttr>:$dbg_exprs, 1245 DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_ 1246 ); 1247 let summary = "LLVM dialect global."; 1248 let description = [{ 1249 Since MLIR allows for arbitrary operations to be present at the top level, 1250 global variables are defined using the `llvm.mlir.global` operation. Both 1251 global constants and variables can be defined, and the value may also be 1252 initialized in both cases. 1253 1254 There are two forms of initialization syntax. Simple constants that can be 1255 represented as MLIR attributes can be given in-line: 1256 1257 ```mlir 1258 llvm.mlir.global @variable(32.0 : f32) : f32 1259 ``` 1260 1261 This initialization and type syntax is similar to `llvm.mlir.constant` and 1262 may use two types: one for MLIR attribute and another for the LLVM value. 1263 These types must be compatible. 1264 1265 More complex constants that cannot be represented as MLIR attributes can be 1266 given in an initializer region: 1267 1268 ```mlir 1269 // This global is initialized with the equivalent of: 1270 // i32* getelementptr (i32* @g2, i32 2) 1271 llvm.mlir.global constant @int_gep() : !llvm.ptr { 1272 %0 = llvm.mlir.addressof @g2 : !llvm.ptr 1273 %1 = llvm.mlir.constant(2 : i32) : i32 1274 %2 = llvm.getelementptr %0[%1] 1275 : (!llvm.ptr, i32) -> !llvm.ptr, i32 1276 // The initializer region must end with `llvm.return`. 1277 llvm.return %2 : !llvm.ptr 1278 } 1279 ``` 1280 1281 Only one of the initializer attribute or initializer region may be provided. 1282 1283 `llvm.mlir.global` must appear at top-level of the enclosing module. It uses 1284 an @-identifier for its value, which will be uniqued by the module with 1285 respect to other @-identifiers in it. 1286 1287 Examples: 1288 1289 ```mlir 1290 // Global values use @-identifiers. 1291 llvm.mlir.global constant @cst(42 : i32) : i32 1292 1293 // Non-constant values must also be initialized. 1294 llvm.mlir.global @variable(32.0 : f32) : f32 1295 1296 // Strings are expected to be of wrapped LLVM i8 array type and do not 1297 // automatically include the trailing zero. 1298 llvm.mlir.global @string("abc") : !llvm.array<3 x i8> 1299 1300 // For strings globals, the trailing type may be omitted. 1301 llvm.mlir.global constant @no_trailing_type("foo bar") 1302 1303 // A complex initializer is constructed with an initializer region. 1304 llvm.mlir.global constant @int_gep() : !llvm.ptr { 1305 %0 = llvm.mlir.addressof @g2 : !llvm.ptr 1306 %1 = llvm.mlir.constant(2 : i32) : i32 1307 %2 = llvm.getelementptr %0[%1] 1308 : (!llvm.ptr, i32) -> !llvm.ptr, i32 1309 llvm.return %2 : !llvm.ptr 1310 } 1311 ``` 1312 1313 Similarly to functions, globals have a linkage attribute. In the custom 1314 syntax, this attribute is placed between `llvm.mlir.global` and the optional 1315 `constant` keyword. If the attribute is omitted, `external` linkage is 1316 assumed by default. 1317 1318 Examples: 1319 1320 ```mlir 1321 // A constant with internal linkage will not participate in linking. 1322 llvm.mlir.global internal constant @cst(42 : i32) : i32 1323 1324 // By default, "external" linkage is assumed and the global participates in 1325 // symbol resolution at link-time. 1326 llvm.mlir.global @glob(0 : f32) : f32 1327 1328 // Alignment is optional 1329 llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) : !llvm.array<8 x f32> 1330 ``` 1331 1332 Like global variables in LLVM IR, globals can have an (optional) 1333 alignment attribute using keyword `alignment`. The integer value of the 1334 alignment must be a positive integer that is a power of 2. 1335 1336 Examples: 1337 1338 ```mlir 1339 // Alignment is optional 1340 llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) { alignment = 32 : i64 } : !llvm.array<8 x f32> 1341 ``` 1342 1343 }]; 1344 let regions = (region AnyRegion:$initializer); 1345 1346 let builders = [ 1347 OpBuilder<(ins "Type":$type, "bool":$isConstant, "Linkage":$linkage, 1348 "StringRef":$name, "Attribute":$value, 1349 CArg<"uint64_t", "0">:$alignment, 1350 CArg<"unsigned", "0">:$addrSpace, 1351 CArg<"bool", "false">:$dsoLocal, 1352 CArg<"bool", "false">:$thread_local_, 1353 CArg<"SymbolRefAttr", "{}">:$comdat, 1354 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs, 1355 CArg<"ArrayRef<Attribute>", "{}">:$dbgExprs)> 1356 ]; 1357 1358 let extraClassDeclaration = [{ 1359 /// Return the LLVM type of the global. 1360 Type getType() { 1361 return getGlobalType(); 1362 } 1363 /// Return the initializer attribute if it exists, or a null attribute. 1364 Attribute getValueOrNull() { 1365 return getValue().value_or(Attribute()); 1366 } 1367 /// Return the initializer region. This may be empty, but if it is not it 1368 /// terminates in an `llvm.return` op with the initializer value. 1369 Region &getInitializerRegion() { 1370 return getOperation()->getRegion(0); 1371 } 1372 /// Return the initializer block. If the initializer region is empty this 1373 /// is nullptr. If it is not nullptr, it terminates with an `llvm.return` 1374 /// op with the initializer value. 1375 Block *getInitializerBlock() { 1376 return getInitializerRegion().empty() ? 1377 nullptr : &getInitializerRegion().front(); 1378 } 1379 }]; 1380 1381 let hasCustomAssemblyFormat = 1; 1382 let hasVerifier = 1; 1383 let hasRegionVerifier = 1; 1384} 1385 1386def LLVM_GlobalCtorsOp : LLVM_Op<"mlir.global_ctors", [ 1387 DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { 1388 let arguments = (ins FlatSymbolRefArrayAttr 1389 : $ctors, I32ArrayAttr 1390 : $priorities); 1391 let summary = "LLVM dialect global_ctors."; 1392 let description = [{ 1393 Specifies a list of constructor functions and priorities. The functions 1394 referenced by this array will be called in ascending order of priority (i.e. 1395 lowest first) when the module is loaded. The order of functions with the 1396 same priority is not defined. This operation is translated to LLVM's 1397 global_ctors global variable. The initializer functions are run at load 1398 time. The `data` field present in LLVM's global_ctors variable is not 1399 modeled here. 1400 1401 Examples: 1402 1403 ```mlir 1404 llvm.mlir.global_ctors {@ctor} 1405 1406 llvm.func @ctor() { 1407 ... 1408 llvm.return 1409 } 1410 ``` 1411 1412 }]; 1413 let assemblyFormat = "attr-dict"; 1414 let hasVerifier = 1; 1415} 1416 1417def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [ 1418 DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { 1419 let arguments = (ins 1420 FlatSymbolRefArrayAttr:$dtors, 1421 I32ArrayAttr:$priorities 1422 ); 1423 let summary = "LLVM dialect global_dtors."; 1424 let description = [{ 1425 Specifies a list of destructor functions and priorities. The functions 1426 referenced by this array will be called in descending order of priority (i.e. 1427 highest first) when the module is unloaded. The order of functions with the 1428 same priority is not defined. This operation is translated to LLVM's 1429 global_dtors global variable. The `data` field present in LLVM's 1430 global_dtors variable is not modeled here. 1431 1432 Examples: 1433 1434 ```mlir 1435 llvm.func @dtor() { 1436 llvm.return 1437 } 1438 llvm.mlir.global_dtors {@dtor} 1439 ``` 1440 1441 }]; 1442 let assemblyFormat = "attr-dict"; 1443 let hasVerifier = 1; 1444} 1445 1446def LLVM_ComdatSelectorOp : LLVM_Op<"comdat_selector", [Symbol]> { 1447 let arguments = (ins 1448 SymbolNameAttr:$sym_name, 1449 Comdat:$comdat 1450 ); 1451 1452 let summary = "LLVM dialect comdat selector declaration"; 1453 1454 let description = [{ 1455 Provides access to object file COMDAT section/group functionality. 1456 1457 Examples: 1458 ```mlir 1459 llvm.comdat @__llvm_comdat { 1460 llvm.comdat_selector @any any 1461 } 1462 llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64 1463 ``` 1464 }]; 1465 let assemblyFormat = "$sym_name $comdat attr-dict"; 1466} 1467 1468def LLVM_ComdatOp : LLVM_Op<"comdat", [NoTerminator, NoRegionArguments, SymbolTable, Symbol]> { 1469 let arguments = (ins 1470 SymbolNameAttr:$sym_name 1471 ); 1472 let summary = "LLVM dialect comdat region"; 1473 1474 let description = [{ 1475 Provides access to object file COMDAT section/group functionality. 1476 1477 Examples: 1478 ```mlir 1479 llvm.comdat @__llvm_comdat { 1480 llvm.comdat_selector @any any 1481 } 1482 llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64 1483 ``` 1484 }]; 1485 let regions = (region SizedRegion<1>:$body); 1486 1487 1488 let skipDefaultBuilders = 1; 1489 let builders = [OpBuilder<(ins "StringRef":$symName)>]; 1490 1491 let assemblyFormat = "$sym_name $body attr-dict"; 1492 let hasRegionVerifier = 1; 1493} 1494 1495def LLVM_LLVMFuncOp : LLVM_Op<"func", [ 1496 AutomaticAllocationScope, IsolatedFromAbove, FunctionOpInterface 1497 ]> { 1498 let summary = "LLVM dialect function."; 1499 1500 let description = [{ 1501 MLIR functions are defined by an operation that is not built into the IR 1502 itself. The LLVM dialect provides an `llvm.func` operation to define 1503 functions compatible with LLVM IR. These functions have LLVM dialect 1504 function type but use MLIR syntax to express it. They are required to have 1505 exactly one result type. LLVM function operation is intended to capture 1506 additional properties of LLVM functions, such as linkage and calling 1507 convention, that may be modeled differently by the built-in MLIR function. 1508 1509 ```mlir 1510 // The type of @bar is !llvm<"i64 (i64)"> 1511 llvm.func @bar(%arg0: i64) -> i64 { 1512 llvm.return %arg0 : i64 1513 } 1514 1515 // Type type of @foo is !llvm<"void (i64)"> 1516 // !llvm.void type is omitted 1517 llvm.func @foo(%arg0: i64) { 1518 llvm.return 1519 } 1520 1521 // A function with `internal` linkage. 1522 llvm.func internal @internal_func() { 1523 llvm.return 1524 } 1525 ``` 1526 }]; 1527 1528 let arguments = (ins 1529 StrAttr:$sym_name, 1530 OptionalAttr<StrAttr>:$sym_visibility, 1531 TypeAttrOf<LLVM_FunctionType>:$function_type, 1532 DefaultValuedAttr<Linkage, "Linkage::External">:$linkage, 1533 UnitAttr:$dso_local, 1534 DefaultValuedAttr<CConv, "CConv::C">:$CConv, 1535 OptionalAttr<SymbolRefAttr>:$comdat, 1536 OptionalAttr<UnitAttr>:$convergent, 1537 OptionalAttr<FlatSymbolRefAttr>:$personality, 1538 OptionalAttr<StrAttr>:$garbageCollector, 1539 OptionalAttr<ArrayAttr>:$passthrough, 1540 OptionalAttr<DictArrayAttr>:$arg_attrs, 1541 OptionalAttr<DictArrayAttr>:$res_attrs, 1542 OptionalAttr<I64Attr>:$function_entry_count, 1543 OptionalAttr<LLVM_MemoryEffectsAttr>:$memory_effects, 1544 DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_, 1545 OptionalAttr<UnitAttr>:$arm_streaming, 1546 OptionalAttr<UnitAttr>:$arm_locally_streaming, 1547 OptionalAttr<UnitAttr>:$arm_streaming_compatible, 1548 OptionalAttr<UnitAttr>:$arm_new_za, 1549 OptionalAttr<UnitAttr>:$arm_in_za, 1550 OptionalAttr<UnitAttr>:$arm_out_za, 1551 OptionalAttr<UnitAttr>:$arm_inout_za, 1552 OptionalAttr<UnitAttr>:$arm_preserves_za, 1553 OptionalAttr<StrAttr>:$section, 1554 OptionalAttr<UnnamedAddr>:$unnamed_addr, 1555 OptionalAttr<I64Attr>:$alignment, 1556 OptionalAttr<LLVM_VScaleRangeAttr>:$vscale_range, 1557 OptionalAttr<FramePointerKindAttr>:$frame_pointer, 1558 OptionalAttr<StrAttr>:$target_cpu, 1559 OptionalAttr<StrAttr>:$tune_cpu, 1560 OptionalAttr<LLVM_TargetFeaturesAttr>:$target_features, 1561 OptionalAttr<BoolAttr>:$unsafe_fp_math, 1562 OptionalAttr<BoolAttr>:$no_infs_fp_math, 1563 OptionalAttr<BoolAttr>:$no_nans_fp_math, 1564 OptionalAttr<BoolAttr>:$approx_func_fp_math, 1565 OptionalAttr<BoolAttr>:$no_signed_zeros_fp_math, 1566 OptionalAttr<StrAttr>:$denormal_fp_math, 1567 OptionalAttr<StrAttr>:$denormal_fp_math_f32, 1568 OptionalAttr<StrAttr>:$fp_contract, 1569 OptionalAttr<UnitAttr>:$no_inline, 1570 OptionalAttr<UnitAttr>:$always_inline, 1571 OptionalAttr<UnitAttr>:$no_unwind, 1572 OptionalAttr<UnitAttr>:$will_return, 1573 OptionalAttr<UnitAttr>:$optimize_none, 1574 OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint, 1575 OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint, 1576 OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size, 1577 OptionalAttr<I32Attr>:$intel_reqd_sub_group_size 1578 ); 1579 1580 let regions = (region AnyRegion:$body); 1581 1582 let skipDefaultBuilders = 1; 1583 1584 let builders = [ 1585 OpBuilder<(ins "StringRef":$name, "Type":$type, 1586 CArg<"Linkage", "Linkage::External">:$linkage, 1587 CArg<"bool", "false">:$dsoLocal, 1588 CArg<"CConv", "CConv::C">:$cconv, 1589 CArg<"SymbolRefAttr", "{}">:$comdat, 1590 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs, 1591 CArg<"ArrayRef<DictionaryAttr>", "{}">:$argAttrs, 1592 CArg<"std::optional<uint64_t>", "{}">:$functionEntryCount)> 1593 ]; 1594 1595 let extraClassDeclaration = [{ 1596 // Add an entry block to an empty function, and set up the block arguments 1597 // to match the signature of the function. 1598 Block *addEntryBlock(OpBuilder &builder); 1599 1600 bool isVarArg() { return getFunctionType().isVarArg(); } 1601 1602 /// Returns the argument types of this function. 1603 ArrayRef<Type> getArgumentTypes() { return getFunctionType().getParams(); } 1604 1605 /// Returns the result types of this function. 1606 ArrayRef<Type> getResultTypes() { 1607 if (::llvm::isa<LLVM::LLVMVoidType>(getFunctionType().getReturnType())) 1608 return {}; 1609 return getFunctionType().getReturnTypes(); 1610 } 1611 1612 /// Returns the callable region, which is the function body. If the function 1613 /// is external, returns null. 1614 Region *getCallableRegion(); 1615 1616 /// Returns true if the `no_inline` attribute is set, false otherwise. 1617 bool isNoInline() { return bool(getNoInlineAttr()); } 1618 1619 /// Returns true if the `always_inline` attribute is set, false otherwise. 1620 bool isAlwaysInline() { return bool(getAlwaysInlineAttr()); } 1621 1622 /// Returns true if the `optimize_none` attribute is set, false otherwise. 1623 bool isOptimizeNone() { return bool(getOptimizeNoneAttr()); } 1624 }]; 1625 1626 let hasCustomAssemblyFormat = 1; 1627 let hasVerifier = 1; 1628 let hasRegionVerifier = 1; 1629} 1630 1631def LLVM_NoneTokenOp 1632 : LLVM_Op<"mlir.none", [Pure]> { 1633 let summary = "Defines a value containing an empty token to LLVM type."; 1634 let description = [{ 1635 Unlike LLVM IR, MLIR does not have first-class token values. They must be 1636 explicitly created as SSA values using `llvm.mlir.none`. This operation has 1637 no operands or attributes, and returns a none token value of a wrapped LLVM IR 1638 pointer type. 1639 1640 Examples: 1641 1642 ```mlir 1643 %0 = llvm.mlir.none : !llvm.token 1644 ``` 1645 }]; 1646 1647 string llvmBuilder = [{ 1648 $res = llvm::ConstantTokenNone::get(builder.getContext()); 1649 }]; 1650 1651 let results = (outs LLVM_TokenType:$res); 1652 let builders = [LLVM_OneResultOpBuilder]; 1653 let assemblyFormat = "attr-dict `:` type($res)"; 1654} 1655 1656def LLVM_UndefOp : LLVM_Op<"mlir.undef", [Pure, ConstantLike]>, 1657 LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> { 1658 let summary = "Creates an undefined value of LLVM dialect type."; 1659 let description = [{ 1660 Unlike LLVM IR, MLIR does not have first-class undefined values. Such values 1661 must be created as SSA values using `llvm.mlir.undef`. This operation has no 1662 operands or attributes. It creates an undefined value of the specified LLVM 1663 IR dialect type. 1664 1665 Example: 1666 1667 ```mlir 1668 // Create a structure with a 32-bit integer followed by a float. 1669 %0 = llvm.mlir.undef : !llvm.struct<(i32, f32)> 1670 ``` 1671 }]; 1672 let results = (outs LLVM_Type:$res); 1673 let builders = [LLVM_OneResultOpBuilder]; 1674 let assemblyFormat = "attr-dict `:` type($res)"; 1675 let hasFolder = 1; 1676} 1677 1678def LLVM_PoisonOp : LLVM_Op<"mlir.poison", [Pure, ConstantLike]>, 1679 LLVM_Builder<"$res = llvm::PoisonValue::get($_resultType);"> { 1680 let summary = "Creates a poison value of LLVM dialect type."; 1681 let description = [{ 1682 Unlike LLVM IR, MLIR does not have first-class poison values. Such values 1683 must be created as SSA values using `llvm.mlir.poison`. This operation has 1684 no operands or attributes. It creates a poison value of the specified LLVM 1685 IR dialect type. 1686 1687 Example: 1688 1689 ```mlir 1690 // Create a poison value for a structure with a 32-bit integer followed 1691 // by a float. 1692 %0 = llvm.mlir.poison : !llvm.struct<(i32, f32)> 1693 ``` 1694 }]; 1695 let results = (outs LLVM_Type:$res); 1696 let builders = [LLVM_OneResultOpBuilder]; 1697 let assemblyFormat = "attr-dict `:` type($res)"; 1698 let hasFolder = 1; 1699} 1700 1701def LLVM_ZeroOp 1702 : LLVM_Op<"mlir.zero", [Pure, ConstantLike]>, 1703 LLVM_Builder<"$res = llvm::Constant::getNullValue($_resultType);"> 1704{ 1705 let summary = "Creates a zero-initialized value of LLVM dialect type."; 1706 let description = [{ 1707 Unlike LLVM IR, MLIR does not have first-class zero-initialized values. 1708 Such values must be created as SSA values using `llvm.mlir.zero`. This 1709 operation has no operands or attributes. It creates a zero-initialized 1710 value of the specified LLVM IR dialect type. 1711 1712 Example: 1713 1714 ```mlir 1715 // Create a zero-initialized value for a structure with a 32-bit integer 1716 // followed by a float. 1717 %0 = llvm.mlir.zero : !llvm.struct<(i32, f32)> 1718 ``` 1719 }]; 1720 let results = (outs LLVM_Type:$res); 1721 let builders = [LLVM_OneResultOpBuilder]; 1722 let assemblyFormat = "attr-dict `:` type($res)"; 1723 let hasVerifier = 1; 1724 let hasFolder = 1; 1725} 1726 1727def LLVM_ConstantOp 1728 : LLVM_Op<"mlir.constant", [Pure, ConstantLike]>, 1729 LLVM_Builder<[{$res = getLLVMConstant($_resultType, $value, $_location, 1730 moduleTranslation);}]> 1731{ 1732 let summary = "Defines a constant of LLVM type."; 1733 let description = [{ 1734 Unlike LLVM IR, MLIR does not have first-class constant values. Therefore, 1735 all constants must be created as SSA values before being used in other 1736 operations. `llvm.mlir.constant` creates such values for scalars, vectors, 1737 strings, and structs. It has a mandatory `value` attribute whose type 1738 depends on the type of the constant value. The type of the constant value 1739 must correspond to the attribute type converted to LLVM IR type. 1740 1741 When creating constant scalars, the `value` attribute must be either an 1742 integer attribute or a floating point attribute. The type of the attribute 1743 may be omitted for `i64` and `f64` types that are implied. 1744 1745 When creating constant vectors, the `value` attribute must be either an 1746 array attribute, a dense attribute, or a sparse attribute that contains 1747 integers or floats. The number of elements in the result vector must match 1748 the number of elements in the attribute. 1749 1750 When creating constant strings, the `value` attribute must be a string 1751 attribute. The type of the constant must be an LLVM array of `i8`s, and the 1752 length of the array must match the length of the attribute. 1753 1754 When creating constant structs, the `value` attribute must be an array 1755 attribute that contains integers or floats. The type of the constant must be 1756 an LLVM struct type. The number of fields in the struct must match the 1757 number of elements in the attribute, and the type of each LLVM struct field 1758 must correspond to the type of the corresponding attribute element converted 1759 to LLVM IR. 1760 1761 Examples: 1762 1763 ```mlir 1764 // Integer constant, internal i32 is mandatory 1765 %0 = llvm.mlir.constant(42 : i32) : i32 1766 1767 // It's okay to omit i64. 1768 %1 = llvm.mlir.constant(42) : i64 1769 1770 // Floating point constant. 1771 %2 = llvm.mlir.constant(42.0 : f32) : f32 1772 1773 // Splat dense vector constant. 1774 %3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : vector<4xf32> 1775 ``` 1776 }]; 1777 1778 let arguments = (ins AnyAttr:$value); 1779 let results = (outs LLVM_Type:$res); 1780 1781 let assemblyFormat = "`(` $value `)` attr-dict `:` type($res)"; 1782 1783 let builders = [ 1784 LLVM_OneResultOpBuilder, 1785 OpBuilder<(ins "Type":$type, "int64_t":$value), [{ 1786 build($_builder, $_state, type, $_builder.getIntegerAttr(type, value)); 1787 }]>, 1788 OpBuilder<(ins "Type":$type, "const APInt &":$value), [{ 1789 build($_builder, $_state, type, $_builder.getIntegerAttr(type, value)); 1790 }]>, 1791 OpBuilder<(ins "Type":$type, "const APFloat &":$value), [{ 1792 build($_builder, $_state, type, $_builder.getFloatAttr(type, value)); 1793 }]>, 1794 OpBuilder<(ins "TypedAttr":$value), [{ 1795 build($_builder, $_state, value.getType(), value); 1796 }]> 1797 ]; 1798 1799 let extraClassDeclaration = [{ 1800 /// Whether the constant op can be constructed with a particular value and 1801 /// type. 1802 static bool isBuildableWith(Attribute value, Type type); 1803 1804 /// Build the constant op with `value` and `type` if possible, otherwise 1805 /// returns null. 1806 static ConstantOp materialize(OpBuilder &builder, Attribute value, 1807 Type type, Location loc); 1808 }]; 1809 1810 let hasFolder = 1; 1811 let hasVerifier = 1; 1812} 1813 1814// Atomic operations. 1815// 1816 1817def LLVM_AtomicRMWType 1818 : AnyTypeOf<[LLVM_AnyFloat, LLVM_AnyPointer, AnySignlessInteger, LLVM_AnyFixedVector]>; 1819 1820def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [ 1821 TypesMatchWith<"result #0 and operand #1 have the same type", 1822 "val", "res", "$_self">]> { 1823 dag args = (ins AtomicBinOp:$bin_op, 1824 LLVM_AnyPointer:$ptr, 1825 LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering, 1826 OptionalAttr<StrAttr>:$syncscope, 1827 OptionalAttr<I64Attr>:$alignment, 1828 UnitAttr:$volatile_); 1829 // Append the aliasing related attributes defined in LLVM_MemAccessOpBase. 1830 let arguments = !con(args, aliasAttrs); 1831 let results = (outs LLVM_AtomicRMWType:$res); 1832 let assemblyFormat = [{ 1833 (`volatile` $volatile_^)? $bin_op $ptr `,` $val 1834 (`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict `:` 1835 qualified(type($ptr)) `,` type($val) 1836 }]; 1837 string llvmInstName = "AtomicRMW"; 1838 string llvmBuilder = [{ 1839 auto *inst = builder.CreateAtomicRMW( 1840 convertAtomicBinOpToLLVM($bin_op), $ptr, $val, llvm::MaybeAlign(), 1841 convertAtomicOrderingToLLVM($ordering)); 1842 $res = inst; 1843 }] # setVolatileCode 1844 # setSyncScopeCode 1845 # setAlignmentCode 1846 # setAccessGroupsMetadataCode 1847 # setAliasAnalysisMetadataCode; 1848 string mlirBuilder = [{ 1849 auto *atomicInst = cast<llvm::AtomicRMWInst>(inst); 1850 unsigned alignment = atomicInst->getAlign().value(); 1851 $res = $_builder.create<LLVM::AtomicRMWOp>($_location, 1852 convertAtomicBinOpFromLLVM(atomicInst->getOperation()), $ptr, $val, 1853 convertAtomicOrderingFromLLVM(atomicInst->getOrdering()), 1854 getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile()); 1855 }]; 1856 list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1]; 1857 let builders = [ 1858 OpBuilder<(ins "LLVM::AtomicBinOp":$binOp, "Value":$ptr, "Value":$val, 1859 "LLVM::AtomicOrdering":$ordering, 1860 CArg<"StringRef", "StringRef()">:$syncscope, 1861 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile 1862 )> 1863 ]; 1864 let hasVerifier = 1; 1865} 1866 1867def LLVM_AtomicCmpXchgType : AnyTypeOf<[AnySignlessInteger, LLVM_AnyPointer]>; 1868 1869def LLVM_AtomicCmpXchgOp : LLVM_MemAccessOpBase<"cmpxchg", [ 1870 TypesMatchWith<"operand #1 and operand #2 have the same type", 1871 "val", "cmp", "$_self">, 1872 TypesMatchWith<"result #0 has an LLVM struct type consisting of " 1873 "the type of operand #2 and a bool", "val", "res", 1874 "getValAndBoolStructType($_self)">]> { 1875 dag args = (ins LLVM_AnyPointer:$ptr, 1876 LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val, 1877 AtomicOrdering:$success_ordering, 1878 AtomicOrdering:$failure_ordering, 1879 OptionalAttr<StrAttr>:$syncscope, 1880 OptionalAttr<I64Attr>:$alignment, 1881 UnitAttr:$weak, 1882 UnitAttr:$volatile_); 1883 // Append the aliasing related attributes defined in LLVM_MemAccessOpBase. 1884 let arguments = !con(args, aliasAttrs); 1885 let results = (outs LLVM_AnyStruct:$res); 1886 let assemblyFormat = [{ 1887 (`weak` $weak^)? (`volatile` $volatile_^)? $ptr `,` $cmp `,` $val 1888 (`syncscope` `(` $syncscope^ `)`)? $success_ordering $failure_ordering 1889 attr-dict `:` qualified(type($ptr)) `,` type($val) 1890 }]; 1891 string llvmInstName = "AtomicCmpXchg"; 1892 string llvmBuilder = [{ 1893 auto *inst = builder.CreateAtomicCmpXchg($ptr, $cmp, $val, 1894 llvm::MaybeAlign(), convertAtomicOrderingToLLVM($success_ordering), 1895 convertAtomicOrderingToLLVM($failure_ordering)); 1896 $res = inst; 1897 inst->setWeak($weak); 1898 }] # setVolatileCode 1899 # setSyncScopeCode 1900 # setAlignmentCode 1901 # setAccessGroupsMetadataCode 1902 # setAliasAnalysisMetadataCode; 1903 string mlirBuilder = [{ 1904 auto *cmpXchgInst = cast<llvm::AtomicCmpXchgInst>(inst); 1905 unsigned alignment = cmpXchgInst->getAlign().value(); 1906 $res = $_builder.create<LLVM::AtomicCmpXchgOp>( 1907 $_location, $ptr, $cmp, $val, 1908 convertAtomicOrderingFromLLVM(cmpXchgInst->getSuccessOrdering()), 1909 convertAtomicOrderingFromLLVM(cmpXchgInst->getFailureOrdering()), 1910 getLLVMSyncScope(cmpXchgInst), alignment, cmpXchgInst->isWeak(), 1911 cmpXchgInst->isVolatile()); 1912 }]; 1913 let builders = [ 1914 OpBuilder<(ins "Value":$ptr, "Value":$cmp, "Value":$val, 1915 "LLVM::AtomicOrdering":$successOrdering, 1916 "LLVM::AtomicOrdering":$failureOrdering, 1917 CArg<"StringRef", "StringRef()">:$syncscope, 1918 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isWeak, 1919 CArg<"bool", "false">:$isVolatile 1920 )> 1921 ]; 1922 let hasVerifier = 1; 1923} 1924 1925def LLVM_FenceOp : LLVM_Op<"fence">, LLVM_MemOpPatterns { 1926 let arguments = (ins AtomicOrdering:$ordering, 1927 OptionalAttr<StrAttr>:$syncscope); 1928 let assemblyFormat = "(`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict"; 1929 string llvmInstName = "Fence"; 1930 let llvmBuilder = [{ 1931 auto *inst = builder.CreateFence(convertAtomicOrderingToLLVM($ordering)); 1932 }] # setSyncScopeCode; 1933 string mlirBuilder = [{ 1934 llvm::FenceInst *fenceInst = cast<llvm::FenceInst>(inst); 1935 $_op = $_builder.create<LLVM::FenceOp>( 1936 $_location, 1937 convertAtomicOrderingFromLLVM(fenceInst->getOrdering()), 1938 getLLVMSyncScope(fenceInst)); 1939 }]; 1940 let builders = [ 1941 LLVM_VoidResultTypeOpBuilder, 1942 LLVM_ZeroResultOpBuilder, 1943 OpBuilder<(ins "LLVM::AtomicOrdering":$ordering, 1944 CArg<"StringRef", "StringRef()">:$syncscope)> 1945 ]; 1946 let hasVerifier = 1; 1947} 1948 1949def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> { 1950 let description = [{ 1951 The InlineAsmOp mirrors the underlying LLVM semantics with a notable 1952 exception: the embedded `asm_string` is not allowed to define or reference 1953 any symbol or any global variable: only the operands of the op may be read, 1954 written, or referenced. 1955 Attempting to define or reference any symbol or any global behavior is 1956 considered undefined behavior at this time. 1957 }]; 1958 let arguments = ( 1959 ins Variadic<LLVM_Type>:$operands, 1960 StrAttr:$asm_string, 1961 StrAttr:$constraints, 1962 UnitAttr:$has_side_effects, 1963 UnitAttr:$is_align_stack, 1964 OptionalAttr< 1965 DefaultValuedAttr<AsmATTOrIntel, "AsmDialect::AD_ATT">>:$asm_dialect, 1966 OptionalAttr<ArrayAttr>:$operand_attrs); 1967 1968 let results = (outs Optional<LLVM_Type>:$res); 1969 1970 let assemblyFormat = [{ 1971 (`has_side_effects` $has_side_effects^)? 1972 (`is_align_stack` $is_align_stack^)? 1973 (`asm_dialect` `=` $asm_dialect^)? 1974 (`operand_attrs` `=` $operand_attrs^)? 1975 attr-dict 1976 $asm_string `,` $constraints 1977 operands `:` functional-type(operands, results) 1978 }]; 1979 1980 let extraClassDeclaration = [{ 1981 static StringRef getElementTypeAttrName() { 1982 return "elementtype"; 1983 } 1984 }]; 1985} 1986 1987//===--------------------------------------------------------------------===// 1988// CallIntrinsicOp 1989//===--------------------------------------------------------------------===// 1990 1991def LLVM_CallIntrinsicOp 1992 : LLVM_Op<"call_intrinsic", 1993 [AttrSizedOperandSegments, 1994 DeclareOpInterfaceMethods<FastmathFlagsInterface>]> { 1995 let summary = "Call to an LLVM intrinsic function."; 1996 let description = [{ 1997 Call the specified llvm intrinsic. If the intrinsic is overloaded, use 1998 the MLIR function type of this op to determine which intrinsic to call. 1999 }]; 2000 let arguments = (ins StrAttr:$intrin, Variadic<LLVM_Type>:$args, 2001 DefaultValuedAttr<LLVM_FastmathFlagsAttr, 2002 "{}">:$fastmathFlags, 2003 VariadicOfVariadic<LLVM_Type, 2004 "op_bundle_sizes">:$op_bundle_operands, 2005 DenseI32ArrayAttr:$op_bundle_sizes, 2006 OptionalAttr<ArrayAttr>:$op_bundle_tags); 2007 let results = (outs Optional<LLVM_Type>:$results); 2008 let llvmBuilder = [{ 2009 return convertCallLLVMIntrinsicOp(op, builder, moduleTranslation); 2010 }]; 2011 let assemblyFormat = [{ 2012 $intrin `(` $args `)` 2013 ( custom<OpBundles>($op_bundle_operands, type($op_bundle_operands), 2014 $op_bundle_tags)^ )? 2015 `:` functional-type($args, $results) 2016 attr-dict 2017 }]; 2018 2019 let builders = [ 2020 OpBuilder<(ins "StringAttr":$intrin, "ValueRange":$args)>, 2021 OpBuilder<(ins "StringAttr":$intrin, "ValueRange":$args, "FastmathFlagsAttr":$fastMathFlags)>, 2022 OpBuilder<(ins "Type": $resultType, "StringAttr":$intrin, "ValueRange":$args)>, 2023 OpBuilder<(ins "TypeRange": $resultTypes, "StringAttr":$intrin, "ValueRange":$args, "FastmathFlagsAttr":$fastMathFlags)> 2024 ]; 2025 2026 let hasVerifier = 1; 2027} 2028 2029def LLVM_LinkerOptionsOp 2030 : LLVM_Op<"linker_options"> { 2031 let summary = "Options to pass to the linker when the object file is linked"; 2032 let description = [{ 2033 Pass the given options to the linker when the resulting object file is linked. 2034 This is used extensively on Windows to determine the C runtime that the object 2035 files should link against. 2036 2037 Examples: 2038 ```mlir 2039 // Link against the MSVC static threaded CRT. 2040 llvm.linker_options ["/DEFAULTLIB:", "libcmt"] 2041 2042 // Link against aarch64 compiler-rt builtins 2043 llvm.linker_options ["-l", "clang_rt.builtins-aarch64"] 2044 ``` 2045 }]; 2046 let arguments = (ins StrArrayAttr:$options); 2047 let assemblyFormat = [{ 2048 $options attr-dict 2049 }]; 2050 2051 let llvmBuilder = [{ 2052 convertLinkerOptionsOp($options, builder, moduleTranslation); 2053 }]; 2054 2055 let hasVerifier = 1; 2056} 2057 2058#endif // LLVMIR_OPS 2059