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/LLVMOpBase.td" 17include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.td" 18include "mlir/IR/SymbolInterfaces.td" 19include "mlir/Interfaces/ControlFlowInterfaces.td" 20include "mlir/Interfaces/SideEffectInterfaces.td" 21 22def FMFnnan : BitEnumAttrCase<"nnan", 0x1>; 23def FMFninf : BitEnumAttrCase<"ninf", 0x2>; 24def FMFnsz : BitEnumAttrCase<"nsz", 0x4>; 25def FMFarcp : BitEnumAttrCase<"arcp", 0x8>; 26def FMFcontract : BitEnumAttrCase<"contract", 0x10>; 27def FMFafn : BitEnumAttrCase<"afn", 0x20>; 28def FMFreassoc : BitEnumAttrCase<"reassoc", 0x40>; 29def FMFfast : BitEnumAttrCase<"fast", 0x80>; 30 31def FastmathFlags : BitEnumAttr< 32 "FastmathFlags", 33 "LLVM fastmath flags", 34 [FMFnnan, FMFninf, FMFnsz, FMFarcp, FMFcontract, FMFafn, FMFreassoc, FMFfast 35 ]> { 36 let cppNamespace = "::mlir::LLVM"; 37} 38 39def LLVM_FMFAttr : DialectAttr< 40 LLVM_Dialect, 41 CPred<"$_self.isa<::mlir::LLVM::FMFAttr>()">, 42 "LLVM fastmath flags"> { 43 let storageType = "::mlir::LLVM::FMFAttr"; 44 let returnType = "::mlir::LLVM::FastmathFlags"; 45 let convertFromStorage = "$_self.getFlags()"; 46 let constBuilderCall = 47 "::mlir::LLVM::FMFAttr::get($_builder.getContext(), $0)"; 48} 49 50def LOptDisableUnroll : I32EnumAttrCase<"disable_unroll", 1>; 51def LOptDisableLICM : I32EnumAttrCase<"disable_licm", 2>; 52def LOptInterleaveCount : I32EnumAttrCase<"interleave_count", 3>; 53def LOptDisablePipeline : I32EnumAttrCase<"disable_pipeline", 4>; 54def LOptPipelineInitiationInterval : I32EnumAttrCase<"pipeline_initiation_interval", 5>; 55 56def LoopOptionCase : I32EnumAttr< 57 "LoopOptionCase", 58 "LLVM loop option", 59 [LOptDisableUnroll, LOptDisableLICM, LOptInterleaveCount, 60 LOptDisablePipeline, LOptPipelineInitiationInterval 61 ]> { 62 let cppNamespace = "::mlir::LLVM"; 63} 64 65class LLVM_Builder<string builder> { 66 string llvmBuilder = builder; 67} 68 69def LLVM_OneResultOpBuilder : 70 OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, 71 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 72 [{ 73 if (resultType) $_state.addTypes(resultType); 74 $_state.addOperands(operands); 75 for (auto namedAttr : attributes) { 76 $_state.addAttribute(namedAttr.first, namedAttr.second); 77 } 78 }]>; 79 80def LLVM_ZeroResultOpBuilder : 81 OpBuilder<(ins "ValueRange":$operands, 82 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 83 [{ 84 $_state.addOperands(operands); 85 for (auto namedAttr : attributes) { 86 $_state.addAttribute(namedAttr.first, namedAttr.second); 87 } 88 }]>; 89 90// Compatibility builder that takes an instance of wrapped llvm::VoidType 91// to indicate no result. 92def LLVM_VoidResultTypeOpBuilder : 93 OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, 94 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 95 [{ 96 assert(isCompatibleType(resultType) && "result must be an LLVM type"); 97 assert(resultType.isa<LLVMVoidType>() && 98 "for zero-result operands, only 'void' is accepted as result type"); 99 build($_builder, $_state, operands, attributes); 100 }]>; 101 102 103// Opaque builder used for terminator operations that contain successors. 104def LLVM_TerminatorPassthroughOpBuilder : 105 OpBuilder<(ins "ValueRange":$operands, "SuccessorRange":$destinations, 106 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 107 [{ 108 $_state.addOperands(operands); 109 $_state.addSuccessors(destinations); 110 $_state.addAttributes(attributes); 111 }]>; 112 113// Base class for LLVM terminator operations. All terminator operations have 114// zero results and an optional list of successors. 115class LLVM_TerminatorOp<string mnemonic, list<OpTrait> traits = []> : 116 LLVM_Op<mnemonic, !listconcat(traits, [Terminator])>; 117 118// Class for arithmetic binary operations. 119class LLVM_ArithmeticOpBase<Type type, string mnemonic, 120 string builderFunc, list<OpTrait> traits = []> : 121 LLVM_Op<mnemonic, 122 !listconcat([NoSideEffect, SameOperandsAndResultType], traits)>, 123 LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> { 124 dag commonArgs = (ins LLVM_ScalarOrVectorOf<type>:$lhs, 125 LLVM_ScalarOrVectorOf<type>:$rhs); 126 let results = (outs LLVM_ScalarOrVectorOf<type>:$res); 127 let builders = [LLVM_OneResultOpBuilder]; 128 let assemblyFormat = "$lhs `,` $rhs custom<LLVMOpAttrs>(attr-dict) `:` type($res)"; 129} 130class LLVM_IntArithmeticOp<string mnemonic, string builderFunc, 131 list<OpTrait> traits = []> : 132 LLVM_ArithmeticOpBase<AnyInteger, mnemonic, builderFunc, traits> { 133 let arguments = commonArgs; 134} 135class LLVM_FloatArithmeticOp<string mnemonic, string builderFunc, 136 list<OpTrait> traits = []> : 137 LLVM_ArithmeticOpBase<LLVM_AnyFloat, mnemonic, builderFunc, 138 !listconcat([DeclareOpInterfaceMethods<FastmathFlagsInterface>], traits)> { 139 dag fmfArg = (ins DefaultValuedAttr<LLVM_FMFAttr, "{}">:$fastmathFlags); 140 let arguments = !con(commonArgs, fmfArg); 141} 142 143// Class for arithmetic unary operations. 144class LLVM_UnaryFloatArithmeticOp<Type type, string mnemonic, 145 string builderFunc, list<OpTrait> traits = []> : 146 LLVM_Op<mnemonic, 147 !listconcat([NoSideEffect, SameOperandsAndResultType, DeclareOpInterfaceMethods<FastmathFlagsInterface>], traits)>, 148 LLVM_Builder<"$res = builder." # builderFunc # "($operand);"> { 149 let arguments = (ins type:$operand, DefaultValuedAttr<LLVM_FMFAttr, "{}">:$fastmathFlags); 150 let results = (outs type:$res); 151 let builders = [LLVM_OneResultOpBuilder]; 152 let assemblyFormat = "$operand custom<LLVMOpAttrs>(attr-dict) `:` type($res)"; 153} 154 155// Integer binary operations. 156def LLVM_AddOp : LLVM_IntArithmeticOp<"add", "CreateAdd", [Commutative]>; 157def LLVM_SubOp : LLVM_IntArithmeticOp<"sub", "CreateSub">; 158def LLVM_MulOp : LLVM_IntArithmeticOp<"mul", "CreateMul", [Commutative]>; 159def LLVM_UDivOp : LLVM_IntArithmeticOp<"udiv", "CreateUDiv">; 160def LLVM_SDivOp : LLVM_IntArithmeticOp<"sdiv", "CreateSDiv">; 161def LLVM_URemOp : LLVM_IntArithmeticOp<"urem", "CreateURem">; 162def LLVM_SRemOp : LLVM_IntArithmeticOp<"srem", "CreateSRem">; 163def LLVM_AndOp : LLVM_IntArithmeticOp<"and", "CreateAnd">; 164def LLVM_OrOp : LLVM_IntArithmeticOp<"or", "CreateOr">; 165def LLVM_XOrOp : LLVM_IntArithmeticOp<"xor", "CreateXor">; 166def LLVM_ShlOp : LLVM_IntArithmeticOp<"shl", "CreateShl">; 167def LLVM_LShrOp : LLVM_IntArithmeticOp<"lshr", "CreateLShr">; 168def LLVM_AShrOp : LLVM_IntArithmeticOp<"ashr", "CreateAShr">; 169 170// Predicate for integer comparisons. 171def ICmpPredicateEQ : I64EnumAttrCase<"eq", 0>; 172def ICmpPredicateNE : I64EnumAttrCase<"ne", 1>; 173def ICmpPredicateSLT : I64EnumAttrCase<"slt", 2>; 174def ICmpPredicateSLE : I64EnumAttrCase<"sle", 3>; 175def ICmpPredicateSGT : I64EnumAttrCase<"sgt", 4>; 176def ICmpPredicateSGE : I64EnumAttrCase<"sge", 5>; 177def ICmpPredicateULT : I64EnumAttrCase<"ult", 6>; 178def ICmpPredicateULE : I64EnumAttrCase<"ule", 7>; 179def ICmpPredicateUGT : I64EnumAttrCase<"ugt", 8>; 180def ICmpPredicateUGE : I64EnumAttrCase<"uge", 9>; 181def ICmpPredicate : I64EnumAttr< 182 "ICmpPredicate", 183 "llvm.icmp comparison predicate", 184 [ICmpPredicateEQ, ICmpPredicateNE, ICmpPredicateSLT, ICmpPredicateSLE, 185 ICmpPredicateSGT, ICmpPredicateSGE, ICmpPredicateULT, ICmpPredicateULE, 186 ICmpPredicateUGT, ICmpPredicateUGE]> { 187 let cppNamespace = "::mlir::LLVM"; 188} 189 190// Other integer operations. 191def LLVM_ICmpOp : LLVM_Op<"icmp", [NoSideEffect]> { 192 let arguments = (ins ICmpPredicate:$predicate, 193 AnyTypeOf<[LLVM_ScalarOrVectorOf<AnyInteger>, LLVM_ScalarOrVectorOf<LLVM_AnyPointer>]>:$lhs, 194 AnyTypeOf<[LLVM_ScalarOrVectorOf<AnyInteger>, LLVM_ScalarOrVectorOf<LLVM_AnyPointer>]>:$rhs); 195 let results = (outs LLVM_ScalarOrVectorOf<I1>:$res); 196 let llvmBuilder = [{ 197 $res = builder.CreateICmp(getLLVMCmpPredicate($predicate), $lhs, $rhs); 198 }]; 199 let builders = [ 200 OpBuilder<(ins "ICmpPredicate":$predicate, "Value":$lhs, "Value":$rhs), 201 [{ 202 build($_builder, $_state, IntegerType::get(lhs.getType().getContext(), 1), 203 predicate, lhs, rhs); 204 }]>]; 205 let parser = [{ return parseCmpOp<ICmpPredicate>(parser, result); }]; 206 let printer = [{ printICmpOp(p, *this); }]; 207} 208 209// Predicate for float comparisons 210def FCmpPredicateFALSE : I64EnumAttrCase<"_false", 0>; 211def FCmpPredicateOEQ : I64EnumAttrCase<"oeq", 1>; 212def FCmpPredicateOGT : I64EnumAttrCase<"ogt", 2>; 213def FCmpPredicateOGE : I64EnumAttrCase<"oge", 3>; 214def FCmpPredicateOLT : I64EnumAttrCase<"olt", 4>; 215def FCmpPredicateOLE : I64EnumAttrCase<"ole", 5>; 216def FCmpPredicateONE : I64EnumAttrCase<"one", 6>; 217def FCmpPredicateORD : I64EnumAttrCase<"ord", 7>; 218def FCmpPredicateUEQ : I64EnumAttrCase<"ueq", 8>; 219def FCmpPredicateUGT : I64EnumAttrCase<"ugt", 9>; 220def FCmpPredicateUGE : I64EnumAttrCase<"uge", 10>; 221def FCmpPredicateULT : I64EnumAttrCase<"ult", 11>; 222def FCmpPredicateULE : I64EnumAttrCase<"ule", 12>; 223def FCmpPredicateUNE : I64EnumAttrCase<"une", 13>; 224def FCmpPredicateUNO : I64EnumAttrCase<"uno", 14>; 225def FCmpPredicateTRUE : I64EnumAttrCase<"_true", 15>; 226 227def FCmpPredicate : I64EnumAttr< 228 "FCmpPredicate", 229 "llvm.fcmp comparison predicate", 230 [FCmpPredicateFALSE, FCmpPredicateOEQ, FCmpPredicateOGT, FCmpPredicateOGE, 231 FCmpPredicateOLT, FCmpPredicateOLE, FCmpPredicateONE, FCmpPredicateORD, 232 FCmpPredicateUEQ, FCmpPredicateUGT, FCmpPredicateUGE, FCmpPredicateULT, 233 FCmpPredicateULE, FCmpPredicateUNE, FCmpPredicateUNO, FCmpPredicateTRUE 234 ]> { 235 let cppNamespace = "::mlir::LLVM"; 236} 237 238// Other floating-point operations. 239def LLVM_FCmpOp : LLVM_Op<"fcmp", [ 240 NoSideEffect, DeclareOpInterfaceMethods<FastmathFlagsInterface>]> { 241 let arguments = (ins FCmpPredicate:$predicate, 242 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$lhs, 243 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$rhs, 244 DefaultValuedAttr<LLVM_FMFAttr, "{}">:$fastmathFlags); 245 let results = (outs LLVM_ScalarOrVectorOf<I1>:$res); 246 let llvmBuilder = [{ 247 $res = builder.CreateFCmp(getLLVMCmpPredicate($predicate), $lhs, $rhs); 248 }]; 249 let parser = [{ return parseCmpOp<FCmpPredicate>(parser, result); }]; 250 let printer = [{ printFCmpOp(p, *this); }]; 251} 252 253// Floating point binary operations. 254def LLVM_FAddOp : LLVM_FloatArithmeticOp<"fadd", "CreateFAdd">; 255def LLVM_FSubOp : LLVM_FloatArithmeticOp<"fsub", "CreateFSub">; 256def LLVM_FMulOp : LLVM_FloatArithmeticOp<"fmul", "CreateFMul">; 257def LLVM_FDivOp : LLVM_FloatArithmeticOp<"fdiv", "CreateFDiv">; 258def LLVM_FRemOp : LLVM_FloatArithmeticOp<"frem", "CreateFRem">; 259def LLVM_FNegOp : LLVM_UnaryFloatArithmeticOp< 260 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, "fneg", "CreateFNeg">; 261 262// Common code definition that is used to verify and set the alignment attribute 263// of LLVM ops that accept such an attribute. 264class MemoryOpWithAlignmentBase { 265 code setAlignmentCode = [{ 266 if ($alignment.hasValue()) { 267 auto align = $alignment.getValue(); 268 if (align != 0) 269 inst->setAlignment(llvm::Align(align)); 270 } 271 }]; 272} 273 274// Code definition that is used for nontemporal metadata creation. 275class MemoryOpWithAlignmentAndAttributes : MemoryOpWithAlignmentBase { 276 code setNonTemporalMetadataCode = [{ 277 if ($nontemporal) { 278 llvm::Module *module = builder.GetInsertBlock()->getModule(); 279 llvm::MDNode *metadata = llvm::MDNode::get( 280 inst->getContext(), llvm::ConstantAsMetadata::get( 281 builder.getInt32(1))); 282 inst->setMetadata(module->getMDKindID("nontemporal"), metadata); 283 } 284 }]; 285 286 code setAccessGroupsMetadataCode = [{ 287 moduleTranslation.setAccessGroupsMetadata(op, inst); 288 }]; 289} 290 291// Memory-related operations. 292def LLVM_AllocaOp : LLVM_Op<"alloca">, MemoryOpWithAlignmentBase { 293 let arguments = (ins AnyInteger:$arraySize, 294 OptionalAttr<I64Attr>:$alignment); 295 let results = (outs LLVM_AnyPointer:$res); 296 string llvmBuilder = [{ 297 auto *inst = builder.CreateAlloca( 298 $_resultType->getPointerElementType(), $arraySize); 299 }] # setAlignmentCode # [{ 300 $res = inst; 301 }]; 302 let builders = [ 303 OpBuilder<(ins "Type":$resultType, "Value":$arraySize, 304 "unsigned":$alignment), 305 [{ 306 if (alignment == 0) 307 return build($_builder, $_state, resultType, arraySize, IntegerAttr()); 308 build($_builder, $_state, resultType, arraySize, 309 $_builder.getI64IntegerAttr(alignment)); 310 }]>]; 311 let parser = [{ return parseAllocaOp(parser, result); }]; 312 let printer = [{ printAllocaOp(p, *this); }]; 313} 314 315def LLVM_GEPOp 316 : LLVM_Op<"getelementptr", [NoSideEffect]>, 317 LLVM_Builder< 318 "$res = builder.CreateGEP(" 319 " $base->getType()->getPointerElementType(), $base, $indices);"> { 320 let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_AnyPointer>:$base, 321 Variadic<LLVM_ScalarOrVectorOf<AnyInteger>>:$indices); 322 let results = (outs LLVM_ScalarOrVectorOf<LLVM_AnyPointer>:$res); 323 let builders = [LLVM_OneResultOpBuilder]; 324 let assemblyFormat = [{ 325 $base `[` $indices `]` attr-dict `:` functional-type(operands, results) 326 }]; 327} 328 329def LLVM_LoadOp : LLVM_Op<"load">, MemoryOpWithAlignmentAndAttributes { 330 let arguments = (ins LLVM_PointerTo<LLVM_LoadableType>:$addr, 331 OptionalAttr<SymbolRefArrayAttr>:$access_groups, 332 OptionalAttr<I64Attr>:$alignment, UnitAttr:$volatile_, 333 UnitAttr:$nontemporal); 334 let results = (outs LLVM_LoadableType:$res); 335 string llvmBuilder = [{ 336 auto *inst = builder.CreateLoad( 337 $addr->getType()->getPointerElementType(), $addr, $volatile_); 338 }] # setAlignmentCode # setNonTemporalMetadataCode # setAccessGroupsMetadataCode # [{ 339 $res = inst; 340 }]; 341 let builders = [ 342 OpBuilder<(ins "Value":$addr, CArg<"unsigned", "0">:$alignment, 343 CArg<"bool", "false">:$isVolatile, CArg<"bool", "false">:$isNonTemporal), 344 [{ 345 auto type = addr.getType().cast<LLVMPointerType>().getElementType(); 346 build($_builder, $_state, type, addr, alignment, isVolatile, isNonTemporal); 347 }]>, 348 OpBuilder<(ins "Type":$t, "Value":$addr, 349 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile, 350 CArg<"bool", "false">:$isNonTemporal)>]; 351 let parser = [{ return parseLoadOp(parser, result); }]; 352 let printer = [{ printLoadOp(p, *this); }]; 353 let verifier = [{ return ::verify(*this); }]; 354} 355 356def LLVM_StoreOp : LLVM_Op<"store">, MemoryOpWithAlignmentAndAttributes { 357 let arguments = (ins LLVM_LoadableType:$value, 358 LLVM_PointerTo<LLVM_LoadableType>:$addr, 359 OptionalAttr<SymbolRefArrayAttr>:$access_groups, 360 OptionalAttr<I64Attr>:$alignment, UnitAttr:$volatile_, 361 UnitAttr:$nontemporal); 362 string llvmBuilder = [{ 363 auto *inst = builder.CreateStore($value, $addr, $volatile_); 364 }] # setAlignmentCode # setNonTemporalMetadataCode # setAccessGroupsMetadataCode; 365 let builders = [ 366 OpBuilder<(ins "Value":$value, "Value":$addr, 367 CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile, 368 CArg<"bool", "false">:$isNonTemporal)> 369 ]; 370 let parser = [{ return parseStoreOp(parser, result); }]; 371 let printer = [{ printStoreOp(p, *this); }]; 372 let verifier = [{ return ::verify(*this); }]; 373} 374 375// Casts. 376class LLVM_CastOp<string mnemonic, string builderFunc, Type type, 377 Type resultType, list<OpTrait> traits = []> : 378 LLVM_Op<mnemonic, !listconcat([NoSideEffect], traits)>, 379 LLVM_Builder<"$res = builder." # builderFunc # "($arg, $_resultType);"> { 380 let arguments = (ins type:$arg); 381 let results = (outs resultType:$res); 382 let builders = [LLVM_OneResultOpBuilder]; 383 let parser = [{ return mlir::impl::parseCastOp(parser, result); }]; 384 let printer = [{ mlir::impl::printCastOp(this->getOperation(), p); }]; 385} 386def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "CreateBitCast", 387 LLVM_AnyNonAggregate, LLVM_AnyNonAggregate>; 388def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "CreateAddrSpaceCast", 389 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>, 390 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>; 391def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "CreateIntToPtr", 392 LLVM_ScalarOrVectorOf<AnyInteger>, 393 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>; 394def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "CreatePtrToInt", 395 LLVM_ScalarOrVectorOf<LLVM_AnyPointer>, 396 LLVM_ScalarOrVectorOf<AnyInteger>>; 397def LLVM_SExtOp : LLVM_CastOp<"sext", "CreateSExt", 398 LLVM_ScalarOrVectorOf<AnyInteger>, 399 LLVM_ScalarOrVectorOf<AnyInteger>>; 400def LLVM_ZExtOp : LLVM_CastOp<"zext", "CreateZExt", 401 LLVM_ScalarOrVectorOf<AnyInteger>, 402 LLVM_ScalarOrVectorOf<AnyInteger>>; 403def LLVM_TruncOp : LLVM_CastOp<"trunc", "CreateTrunc", 404 LLVM_ScalarOrVectorOf<AnyInteger>, 405 LLVM_ScalarOrVectorOf<AnyInteger>>; 406def LLVM_SIToFPOp : LLVM_CastOp<"sitofp", "CreateSIToFP", 407 LLVM_ScalarOrVectorOf<AnyInteger>, 408 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 409def LLVM_UIToFPOp : LLVM_CastOp<"uitofp", "CreateUIToFP", 410 LLVM_ScalarOrVectorOf<AnyInteger>, 411 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 412def LLVM_FPToSIOp : LLVM_CastOp<"fptosi", "CreateFPToSI", 413 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 414 LLVM_ScalarOrVectorOf<AnyInteger>>; 415def LLVM_FPToUIOp : LLVM_CastOp<"fptoui", "CreateFPToUI", 416 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 417 LLVM_ScalarOrVectorOf<AnyInteger>>; 418def LLVM_FPExtOp : LLVM_CastOp<"fpext", "CreateFPExt", 419 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 420 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 421def LLVM_FPTruncOp : LLVM_CastOp<"fptrunc", "CreateFPTrunc", 422 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, 423 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>; 424 425// Call-related operations. 426def LLVM_InvokeOp : LLVM_Op<"invoke", [ 427 AttrSizedOperandSegments, 428 DeclareOpInterfaceMethods<BranchOpInterface>, 429 Terminator]> { 430 let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee, 431 Variadic<LLVM_Type>:$operands, 432 Variadic<LLVM_Type>:$normalDestOperands, 433 Variadic<LLVM_Type>:$unwindDestOperands); 434 let results = (outs Variadic<LLVM_Type>); 435 let successors = (successor AnySuccessor:$normalDest, 436 AnySuccessor:$unwindDest); 437 438 let builders = [ 439 OpBuilder<(ins "TypeRange":$tys, "FlatSymbolRefAttr":$callee, 440 "ValueRange":$ops, "Block*":$normal, "ValueRange":$normalOps, 441 "Block*":$unwind, "ValueRange":$unwindOps), 442 [{ 443 $_state.addAttribute("callee", callee); 444 build($_builder, $_state, tys, ops, normal, normalOps, unwind, unwindOps); 445 }]>, 446 OpBuilder<(ins "TypeRange":$tys, "ValueRange":$ops, "Block*":$normal, 447 "ValueRange":$normalOps, "Block*":$unwind, "ValueRange":$unwindOps), 448 [{ 449 build($_builder, $_state, tys, /*callee=*/FlatSymbolRefAttr(), ops, normalOps, 450 unwindOps, normal, unwind); 451 }]>]; 452 let verifier = [{ return ::verify(*this); }]; 453 let parser = [{ return parseInvokeOp(parser, result); }]; 454 let printer = [{ printInvokeOp(p, *this); }]; 455} 456 457def LLVM_LandingpadOp : LLVM_Op<"landingpad"> { 458 let arguments = (ins UnitAttr:$cleanup, Variadic<LLVM_Type>); 459 let results = (outs LLVM_Type:$res); 460 let builders = [LLVM_OneResultOpBuilder]; 461 let verifier = [{ return ::verify(*this); }]; 462 let parser = [{ return parseLandingpadOp(parser, result); }]; 463 let printer = [{ printLandingpadOp(p, *this); }]; 464} 465 466def LLVM_CallOp : LLVM_Op<"call", 467 [DeclareOpInterfaceMethods<FastmathFlagsInterface>]> { 468 let summary = "Call to an LLVM function."; 469 let description = [{ 470 471 472 In LLVM IR, functions may return either 0 or 1 value. LLVM IR dialect 473 implements this behavior by providing a variadic `call` operation for 0- and 474 1-result functions. Even though MLIR supports multi-result functions, LLVM 475 IR dialect disallows them. 476 477 The `call` instruction supports both direct and indirect calls. Direct calls 478 start with a function name (`@`-prefixed) and indirect calls start with an 479 SSA value (`%`-prefixed). The direct callee, if present, is stored as a 480 function attribute `callee`. The trailing type of the instruction is always 481 the MLIR function type, which may be different from the indirect callee that 482 has the wrapped LLVM IR function type. 483 484 Examples: 485 486 ```mlir 487 // Direct call without arguments and with one result. 488 %0 = llvm.call @foo() : () -> (f32) 489 490 // Direct call with arguments and without a result. 491 llvm.call @bar(%0) : (f32) -> () 492 493 // Indirect call with an argument and without a result. 494 llvm.call %1(%0) : (f32) -> () 495 ``` 496 }]; 497 let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee, 498 Variadic<LLVM_Type>, 499 DefaultValuedAttr<LLVM_FMFAttr, "{}">:$fastmathFlags); 500 let results = (outs Variadic<LLVM_Type>); 501 let builders = [ 502 OpBuilder<(ins "LLVMFuncOp":$func, "ValueRange":$operands, 503 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), 504 [{ 505 Type resultType = func.getType().getReturnType(); 506 if (!resultType.isa<LLVM::LLVMVoidType>()) 507 $_state.addTypes(resultType); 508 $_state.addAttribute("callee", $_builder.getSymbolRefAttr(func)); 509 $_state.addAttributes(attributes); 510 $_state.addOperands(operands); 511 }]>]; 512 let verifier = [{ return ::verify(*this); }]; 513 let parser = [{ return parseCallOp(parser, result); }]; 514 let printer = [{ printCallOp(p, *this); }]; 515} 516def LLVM_ExtractElementOp : LLVM_Op<"extractelement", [NoSideEffect]> { 517 let arguments = (ins LLVM_AnyVector:$vector, AnyInteger:$position); 518 let results = (outs LLVM_Type:$res); 519 string llvmBuilder = [{ 520 $res = builder.CreateExtractElement($vector, $position); 521 }]; 522 let builders = [ 523 OpBuilder<(ins "Value":$vector, "Value":$position, 524 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>]; 525 let verifier = [{ return ::verify(*this); }]; 526 let parser = [{ return parseExtractElementOp(parser, result); }]; 527 let printer = [{ printExtractElementOp(p, *this); }]; 528} 529def LLVM_ExtractValueOp : LLVM_Op<"extractvalue", [NoSideEffect]> { 530 let arguments = (ins LLVM_AnyAggregate:$container, ArrayAttr:$position); 531 let results = (outs LLVM_Type:$res); 532 string llvmBuilder = [{ 533 $res = builder.CreateExtractValue($container, extractPosition($position)); 534 }]; 535 let builders = [LLVM_OneResultOpBuilder]; 536 let verifier = [{ return ::verify(*this); }]; 537 let parser = [{ return parseExtractValueOp(parser, result); }]; 538 let printer = [{ printExtractValueOp(p, *this); }]; 539 let hasFolder = 1; 540} 541def LLVM_InsertElementOp : LLVM_Op<"insertelement", [NoSideEffect]> { 542 let arguments = (ins LLVM_AnyVector:$vector, LLVM_PrimitiveType:$value, 543 AnyInteger:$position); 544 let results = (outs LLVM_AnyVector:$res); 545 string llvmBuilder = [{ 546 $res = builder.CreateInsertElement($vector, $value, $position); 547 }]; 548 let builders = [LLVM_OneResultOpBuilder]; 549 let verifier = [{ return ::verify(*this); }]; 550 let parser = [{ return parseInsertElementOp(parser, result); }]; 551 let printer = [{ printInsertElementOp(p, *this); }]; 552} 553def LLVM_InsertValueOp : LLVM_Op<"insertvalue", [NoSideEffect]> { 554 let arguments = (ins LLVM_AnyAggregate:$container, LLVM_PrimitiveType:$value, 555 ArrayAttr:$position); 556 let results = (outs LLVM_AnyAggregate:$res); 557 string llvmBuilder = [{ 558 $res = builder.CreateInsertValue($container, $value, 559 extractPosition($position)); 560 }]; 561 let builders = [ 562 OpBuilder<(ins "Value":$container, "Value":$value, "ArrayAttr":$position), 563 [{ 564 build($_builder, $_state, container.getType(), container, value, position); 565 }]>]; 566 let verifier = [{ return ::verify(*this); }]; 567 let parser = [{ return parseInsertValueOp(parser, result); }]; 568 let printer = [{ printInsertValueOp(p, *this); }]; 569} 570def LLVM_ShuffleVectorOp : LLVM_Op<"shufflevector", [NoSideEffect]> { 571 let arguments = (ins LLVM_AnyVector:$v1, LLVM_AnyVector:$v2, ArrayAttr:$mask); 572 let results = (outs LLVM_AnyVector:$res); 573 string llvmBuilder = [{ 574 SmallVector<unsigned, 4> position = extractPosition($mask); 575 SmallVector<int, 4> mask(position.begin(), position.end()); 576 $res = builder.CreateShuffleVector($v1, $v2, mask); 577 }]; 578 let builders = [ 579 OpBuilder<(ins "Value":$v1, "Value":$v2, "ArrayAttr":$mask, 580 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>]; 581 let verifier = [{ 582 auto type1 = v1().getType(); 583 auto type2 = v2().getType(); 584 if (::mlir::LLVM::getVectorElementType(type1) != 585 ::mlir::LLVM::getVectorElementType(type2)) 586 return emitOpError("expected matching LLVM IR Dialect element types"); 587 return success(); 588 }]; 589 let parser = [{ return parseShuffleVectorOp(parser, result); }]; 590 let printer = [{ printShuffleVectorOp(p, *this); }]; 591} 592 593// Misc operations. 594def LLVM_SelectOp 595 : LLVM_Op<"select", 596 [NoSideEffect, AllTypesMatch<["trueValue", "falseValue", "res"]>]>, 597 LLVM_Builder< 598 "$res = builder.CreateSelect($condition, $trueValue, $falseValue);"> { 599 let arguments = (ins LLVM_ScalarOrVectorOf<I1>:$condition, 600 LLVM_Type:$trueValue, LLVM_Type:$falseValue); 601 let results = (outs LLVM_Type:$res); 602 let builders = [ 603 OpBuilder<(ins "Value":$condition, "Value":$lhs, "Value":$rhs), 604 [{ 605 build($_builder, $_state, lhs.getType(), condition, lhs, rhs); 606 }]>]; 607 let assemblyFormat = "operands attr-dict `:` type($condition) `,` type($res)"; 608} 609def LLVM_FreezeOp : LLVM_Op<"freeze", [SameOperandsAndResultType]> { 610 let arguments = (ins LLVM_Type:$val); 611 let results = (outs LLVM_Type:$res); 612 let builders = [LLVM_OneResultOpBuilder]; 613 let assemblyFormat = "$val attr-dict `:` type($val)"; 614 string llvmBuilder = "builder.CreateFreeze($val);"; 615} 616 617// Terminators. 618def LLVM_BrOp : LLVM_TerminatorOp<"br", 619 [DeclareOpInterfaceMethods<BranchOpInterface>, NoSideEffect]> { 620 let arguments = (ins Variadic<LLVM_Type>:$destOperands); 621 let successors = (successor AnySuccessor:$dest); 622 let assemblyFormat = [{ 623 $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict 624 }]; 625 let builders = [LLVM_TerminatorPassthroughOpBuilder]; 626} 627def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br", 628 [AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>, 629 NoSideEffect]> { 630 let arguments = (ins I1:$condition, 631 Variadic<LLVM_Type>:$trueDestOperands, 632 Variadic<LLVM_Type>:$falseDestOperands, 633 OptionalAttr<ElementsAttr>:$branch_weights); 634 let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest); 635 let assemblyFormat = [{ 636 $condition ( `weights` `(` $branch_weights^ `)` )? `,` 637 $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,` 638 $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)? 639 attr-dict 640 }]; 641 642 let builders = [ 643 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 644 "ValueRange":$trueOperands, "Block *":$falseDest, 645 "ValueRange":$falseOperands, 646 CArg<"Optional<std::pair<uint32_t, uint32_t>>", "{}">:$weights), 647 [{ 648 ElementsAttr weightsAttr; 649 if (weights) { 650 weightsAttr = 651 $_builder.getI32VectorAttr({static_cast<int32_t>(weights->first), 652 static_cast<int32_t>(weights->second)}); 653 } 654 build($_builder, $_state, condition, trueOperands, falseOperands, weightsAttr, 655 trueDest, falseDest); 656 }]>, 657 OpBuilder<(ins "Value":$condition, "Block *":$trueDest, 658 "Block *":$falseDest, CArg<"ValueRange", "{}">:$falseOperands), 659 [{ 660 build($_builder, $_state, condition, trueDest, ValueRange(), falseDest, 661 falseOperands); 662 }]>, LLVM_TerminatorPassthroughOpBuilder]; 663} 664def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]> { 665 let arguments = (ins Variadic<LLVM_Type>:$args); 666 string llvmBuilder = [{ 667 if ($_numOperands != 0) 668 builder.CreateRet($args[0]); 669 else 670 builder.CreateRetVoid(); 671 }]; 672 673 let verifier = [{ 674 if (getNumOperands() > 1) 675 return emitOpError("expects at most 1 operand"); 676 return success(); 677 }]; 678 679 let parser = [{ return parseReturnOp(parser, result); }]; 680 let printer = [{ printReturnOp(p, *this); }]; 681 let verifier = [{ return ::verify(*this); }]; 682} 683def LLVM_ResumeOp : LLVM_TerminatorOp<"resume", []> { 684 let arguments = (ins LLVM_Type:$value); 685 string llvmBuilder = [{ builder.CreateResume($value); }]; 686 let verifier = [{ 687 if (!isa_and_nonnull<LandingpadOp>(value().getDefiningOp())) 688 return emitOpError("expects landingpad value as operand"); 689 // No check for personality of function - landingpad op verifies it. 690 return success(); 691 }]; 692 693 let assemblyFormat = "$value attr-dict `:` type($value)"; 694} 695def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable", []> { 696 string llvmBuilder = [{ builder.CreateUnreachable(); }]; 697 let parser = [{ return success(); }]; 698 let printer = [{ p << getOperationName(); }]; 699} 700 701def LLVM_SwitchOp : LLVM_TerminatorOp<"switch", 702 [AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>, 703 NoSideEffect]> { 704 let arguments = (ins I32:$value, 705 Variadic<AnyType>:$defaultOperands, 706 Variadic<AnyType>:$caseOperands, 707 OptionalAttr<ElementsAttr>:$case_values, 708 OptionalAttr<ElementsAttr>:$case_operand_offsets, 709 OptionalAttr<ElementsAttr>:$branch_weights); 710 let successors = (successor 711 AnySuccessor:$defaultDestination, 712 VariadicSuccessor<AnySuccessor>:$caseDestinations); 713 714 let verifier = [{ return ::verify(*this); }]; 715 let assemblyFormat = [{ 716 $value `,` 717 $defaultDestination (`(` $defaultOperands^ `:` type($defaultOperands) `)`)? 718 `[` `\n` custom<SwitchOpCases>($case_values, $caseDestinations, 719 $caseOperands, type($caseOperands), 720 $case_operand_offsets) `]` 721 attr-dict 722 }]; 723 724 let builders = [ 725 OpBuilder<(ins "Value":$value, 726 "Block *":$defaultDestination, 727 "ValueRange":$defaultOperands, 728 CArg<"ArrayRef<int32_t>", "{}">:$caseValues, 729 CArg<"BlockRange", "{}">:$caseDestinations, 730 CArg<"ArrayRef<ValueRange>", "{}">:$caseOperands, 731 CArg<"ArrayRef<int32_t>", "{}">:$branchWeights)>, 732 LLVM_TerminatorPassthroughOpBuilder 733 ]; 734 735 let extraClassDeclaration = [{ 736 /// Return the operands for the case destination block at the given index. 737 OperandRange getCaseOperands(unsigned index); 738 739 /// Return a mutable range of operands for the case destination block at the 740 /// given index. 741 MutableOperandRange getCaseOperandsMutable(unsigned index); 742 }]; 743} 744 745//////////////////////////////////////////////////////////////////////////////// 746// Auxiliary operations (do not appear in LLVM IR but necessary for the dialect 747// to work correctly). 748//////////////////////////////////////////////////////////////////////////////// 749 750// Linkage attribute is used on functions and globals. The order follows that of 751// https://llvm.org/docs/LangRef.html#linkage-types. The names are equivalent to 752// visible names in the IR rather than to enum values names in llvm::GlobalValue 753// since the latter is easier to change. 754def LinkagePrivate 755 : LLVM_EnumAttrCase<"Private", "private", "PrivateLinkage", 0>; 756def LinkageInternal 757 : LLVM_EnumAttrCase<"Internal", "internal", "InternalLinkage", 1>; 758def LinkageAvailableExternally 759 : LLVM_EnumAttrCase<"AvailableExternally", "available_externally", 760 "AvailableExternallyLinkage", 2>; 761def LinkageLinkonce 762 : LLVM_EnumAttrCase<"Linkonce", "linkonce", "LinkOnceAnyLinkage", 3>; 763def LinkageWeak 764 : LLVM_EnumAttrCase<"Weak", "weak", "WeakAnyLinkage", 4>; 765def LinkageCommon 766 : LLVM_EnumAttrCase<"Common", "common", "CommonLinkage", 5>; 767def LinkageAppending 768 : LLVM_EnumAttrCase<"Appending", "appending", "AppendingLinkage", 6>; 769def LinkageExternWeak 770 : LLVM_EnumAttrCase<"ExternWeak", "extern_weak", "ExternalWeakLinkage", 7>; 771def LinkageLinkonceODR 772 : LLVM_EnumAttrCase<"LinkonceODR", "linkonce_odr", "LinkOnceODRLinkage", 8>; 773def LinkageWeakODR 774 : LLVM_EnumAttrCase<"WeakODR", "weak_odr", "WeakODRLinkage", 9>; 775def LinkageExternal 776 : LLVM_EnumAttrCase<"External", "external", "ExternalLinkage", 10>; 777 778def Linkage : LLVM_EnumAttr< 779 "Linkage", 780 "::llvm::GlobalValue::LinkageTypes", 781 "LLVM linkage types", 782 [LinkagePrivate, LinkageInternal, LinkageAvailableExternally, 783 LinkageLinkonce, LinkageWeak, LinkageCommon, LinkageAppending, 784 LinkageExternWeak, LinkageLinkonceODR, LinkageWeakODR, LinkageExternal]> { 785 let cppNamespace = "::mlir::LLVM"; 786} 787 788def UnnamedAddrNone : LLVM_EnumAttrCase<"None", "", "None", 0>; 789def UnnamedAddrLocal : LLVM_EnumAttrCase<"Local", "local_unnamed_addr", "Local", 1>; 790def UnnamedAddrGlobal : LLVM_EnumAttrCase<"Global", "unnamed_addr", "Global", 2>; 791 792def UnnamedAddr : LLVM_EnumAttr< 793 "UnnamedAddr", 794 "::llvm::GlobalValue::UnnamedAddr", 795 "LLVM GlobalValue UnnamedAddr", 796 [UnnamedAddrNone, UnnamedAddrLocal, UnnamedAddrGlobal]> { 797 let cppNamespace = "::mlir::LLVM"; 798} 799 800def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof"> { 801 let arguments = (ins FlatSymbolRefAttr:$global_name); 802 let results = (outs LLVM_Type:$res); 803 804 let summary = "Creates a pointer pointing to a global or a function"; 805 806 let description = [{ 807 Creates an SSA value containing a pointer to a global variable or constant 808 defined by `llvm.mlir.global`. The global value can be defined after its 809 first referenced. If the global value is a constant, storing into it is not 810 allowed. 811 812 Examples: 813 814 ```mlir 815 func @foo() { 816 // Get the address of a global variable. 817 %0 = llvm.mlir.addressof @const : !llvm.ptr<i32> 818 819 // Use it as a regular pointer. 820 %1 = llvm.load %0 : !llvm.ptr<i32> 821 822 // Get the address of a function. 823 %2 = llvm.mlir.addressof @foo : !llvm.ptr<func<void ()>> 824 825 // The function address can be used for indirect calls. 826 llvm.call %2() : () -> () 827 } 828 829 // Define the global. 830 llvm.mlir.global @const(42 : i32) : i32 831 ``` 832 }]; 833 834 let builders = [ 835 OpBuilder<(ins "GlobalOp":$global, 836 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs), 837 [{ 838 build($_builder, $_state, 839 LLVM::LLVMPointerType::get(global.getType(), global.addr_space()), 840 global.sym_name()); 841 $_state.addAttributes(attrs); 842 }]>, 843 OpBuilder<(ins "LLVMFuncOp":$func, 844 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs), 845 [{ 846 build($_builder, $_state, 847 LLVM::LLVMPointerType::get(func.getType()), func.getName()); 848 $_state.addAttributes(attrs); 849 }]> 850 ]; 851 852 let extraClassDeclaration = [{ 853 /// Return the llvm.mlir.global operation that defined the value referenced 854 /// here. 855 GlobalOp getGlobal(); 856 857 /// Return the llvm.func operation that is referenced here. 858 LLVMFuncOp getFunction(); 859 }]; 860 861 let assemblyFormat = "$global_name attr-dict `:` type($res)"; 862 let verifier = "return ::verify(*this);"; 863} 864 865def LLVM_MetadataOp : LLVM_Op<"metadata", [ 866 NoRegionArguments, SymbolTable, Symbol 867]> { 868 let arguments = (ins 869 SymbolNameAttr:$sym_name 870 ); 871 let summary = "LLVM dialect metadata."; 872 let description = [{ 873 llvm.metadata op defines one or more metadata nodes. Currently the 874 llvm.access_group metadata op is supported. 875 876 Example: 877 llvm.metadata @metadata { 878 llvm.access_group @group1 879 llvm.access_group @group2 880 llvm.return 881 } 882 }]; 883 let regions = (region SizedRegion<1>:$body); 884 let assemblyFormat = "$sym_name attr-dict-with-keyword $body"; 885} 886 887def LLVM_AccessGroupMetadataOp : LLVM_Op<"access_group", [ 888 HasParent<"MetadataOp">, Symbol 889]> { 890 let arguments = (ins 891 SymbolNameAttr:$sym_name 892 ); 893 let summary = "LLVM dialect access group metadata."; 894 let description = [{ 895 Defines an access group metadata that can be attached to any instruction 896 that potentially accesses memory. The access group may be attached to a 897 memory accessing instruction via the `llvm.access.group` metadata and 898 a branch instruction in the loop latch block via the 899 `llvm.loop.parallel_accesses` metadata. 900 901 See the following link for more details: 902 https://llvm.org/docs/LangRef.html#llvm-access-group-metadata 903 }]; 904 let assemblyFormat = "$sym_name attr-dict"; 905} 906 907def LLVM_GlobalOp : LLVM_Op<"mlir.global", 908 [IsolatedFromAbove, SingleBlockImplicitTerminator<"ReturnOp">, Symbol]> { 909 let arguments = (ins 910 TypeAttr:$type, 911 UnitAttr:$constant, 912 StrAttr:$sym_name, 913 Linkage:$linkage, 914 UnitAttr:$dso_local, 915 OptionalAttr<AnyAttr>:$value, 916 OptionalAttr<I64Attr>:$alignment, 917 DefaultValuedAttr<Confined<I32Attr, [IntNonNegative]>, "0">:$addr_space, 918 OptionalAttr<UnnamedAddr>:$unnamed_addr, 919 OptionalAttr<StrAttr>:$section 920 ); 921 let summary = "LLVM dialect global."; 922 let description = [{ 923 Since MLIR allows for arbitrary operations to be present at the top level, 924 global variables are defined using the `llvm.mlir.global` operation. Both 925 global constants and variables can be defined, and the value may also be 926 initialized in both cases. 927 928 There are two forms of initialization syntax. Simple constants that can be 929 represented as MLIR attributes can be given in-line: 930 931 ```mlir 932 llvm.mlir.global @variable(32.0 : f32) : f32 933 ``` 934 935 This initialization and type syntax is similar to `llvm.mlir.constant` and 936 may use two types: one for MLIR attribute and another for the LLVM value. 937 These types must be compatible. 938 939 More complex constants that cannot be represented as MLIR attributes can be 940 given in an initializer region: 941 942 ```mlir 943 // This global is initialized with the equivalent of: 944 // i32* getelementptr (i32* @g2, i32 2) 945 llvm.mlir.global constant @int_gep() : !llvm.ptr<i32> { 946 %0 = llvm.mlir.addressof @g2 : !llvm.ptr<i32> 947 %1 = llvm.mlir.constant(2 : i32) : i32 948 %2 = llvm.getelementptr %0[%1] 949 : (!llvm.ptr<i32>, i32) -> !llvm.ptr<i32> 950 // The initializer region must end with `llvm.return`. 951 llvm.return %2 : !llvm.ptr<i32> 952 } 953 ``` 954 955 Only one of the initializer attribute or initializer region may be provided. 956 957 `llvm.mlir.global` must appear at top-level of the enclosing module. It uses 958 an @-identifier for its value, which will be uniqued by the module with 959 respect to other @-identifiers in it. 960 961 Examples: 962 963 ```mlir 964 // Global values use @-identifiers. 965 llvm.mlir.global constant @cst(42 : i32) : i32 966 967 // Non-constant values must also be initialized. 968 llvm.mlir.global @variable(32.0 : f32) : f32 969 970 // Strings are expected to be of wrapped LLVM i8 array type and do not 971 // automatically include the trailing zero. 972 llvm.mlir.global @string("abc") : !llvm.array<3 x i8> 973 974 // For strings globals, the trailing type may be omitted. 975 llvm.mlir.global constant @no_trailing_type("foo bar") 976 977 // A complex initializer is constructed with an initializer region. 978 llvm.mlir.global constant @int_gep() : !llvm.ptr<i32> { 979 %0 = llvm.mlir.addressof @g2 : !llvm.ptr<i32> 980 %1 = llvm.mlir.constant(2 : i32) : i32 981 %2 = llvm.getelementptr %0[%1] 982 : (!llvm.ptr<i32>, i32) -> !llvm.ptr<i32> 983 llvm.return %2 : !llvm.ptr<i32> 984 } 985 ``` 986 987 Similarly to functions, globals have a linkage attribute. In the custom 988 syntax, this attribute is placed between `llvm.mlir.global` and the optional 989 `constant` keyword. If the attribute is omitted, `external` linkage is 990 assumed by default. 991 992 Examples: 993 994 ```mlir 995 // A constant with internal linkage will not participate in linking. 996 llvm.mlir.global internal constant @cst(42 : i32) : i32 997 998 // By default, "external" linkage is assumed and the global participates in 999 // symbol resolution at link-time. 1000 llvm.mlir.global @glob(0 : f32) : f32 1001 1002 // Alignment is optional 1003 llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) : !llvm.array<8 x f32> 1004 ``` 1005 1006 Like global variables in LLVM IR, globals can have an (optional) 1007 alignment attribute using keyword `alignment`. The integer value of the 1008 alignment must be a positive integer that is a power of 2. 1009 1010 Examples: 1011 1012 ```mlir 1013 // Alignment is optional 1014 llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) { alignment = 32 : i64 } : !llvm.array<8 x f32> 1015 ``` 1016 1017 }]; 1018 let regions = (region AnyRegion:$initializer); 1019 1020 let builders = [ 1021 OpBuilder<(ins "Type":$type, "bool":$isConstant, "Linkage":$linkage, 1022 "StringRef":$name, "Attribute":$value, 1023 CArg<"uint64_t", "0">:$alignment, 1024 CArg<"unsigned", "0">:$addrSpace, 1025 CArg<"bool", "false">:$dsoLocal, 1026 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)> 1027 ]; 1028 1029 let extraClassDeclaration = [{ 1030 /// Return the LLVM type of the global. 1031 Type getType() { 1032 return type(); 1033 } 1034 /// Return the initializer attribute if it exists, or a null attribute. 1035 Attribute getValueOrNull() { 1036 return value().getValueOr(Attribute()); 1037 } 1038 /// Return the initializer region. This may be empty, but if it is not it 1039 /// terminates in an `llvm.return` op with the initializer value. 1040 Region &getInitializerRegion() { 1041 return getOperation()->getRegion(0); 1042 } 1043 /// Return the initializer block. If the initializer region is empty this 1044 /// is nullptr. If it is not nullptr, it terminates with an `llvm.return` 1045 /// op with the initializer value. 1046 Block *getInitializerBlock() { 1047 return getInitializerRegion().empty() ? 1048 nullptr : &getInitializerRegion().front(); 1049 } 1050 }]; 1051 1052 let printer = "printGlobalOp(p, *this);"; 1053 let parser = "return parseGlobalOp(parser, result);"; 1054 let verifier = "return ::verify(*this);"; 1055} 1056 1057def LLVM_LLVMFuncOp : LLVM_Op<"func", 1058 [AutomaticAllocationScope, IsolatedFromAbove, FunctionLike, Symbol]> { 1059 let summary = "LLVM dialect function."; 1060 1061 let description = [{ 1062 MLIR functions are defined by an operation that is not built into the IR 1063 itself. The LLVM dialect provides an `llvm.func` operation to define 1064 functions compatible with LLVM IR. These functions have LLVM dialect 1065 function type but use MLIR syntax to express it. They are required to have 1066 exactly one result type. LLVM function operation is intended to capture 1067 additional properties of LLVM functions, such as linkage and calling 1068 convention, that may be modeled differently by the built-in MLIR function. 1069 1070 ```mlir 1071 // The type of @bar is !llvm<"i64 (i64)"> 1072 llvm.func @bar(%arg0: i64) -> i64 { 1073 llvm.return %arg0 : i64 1074 } 1075 1076 // Type type of @foo is !llvm<"void (i64)"> 1077 // !llvm.void type is omitted 1078 llvm.func @foo(%arg0: i64) { 1079 llvm.return 1080 } 1081 1082 // A function with `internal` linkage. 1083 llvm.func internal @internal_func() { 1084 llvm.return 1085 } 1086 ``` 1087 }]; 1088 1089 let arguments = (ins DefaultValuedAttr<Linkage, "Linkage::External">:$linkage, 1090 UnitAttr:$dso_local, 1091 OptionalAttr<FlatSymbolRefAttr>:$personality, 1092 OptionalAttr<ArrayAttr>:$passthrough); 1093 1094 let regions = (region AnyRegion:$body); 1095 1096 let skipDefaultBuilders = 1; 1097 1098 let builders = [ 1099 OpBuilder<(ins "StringRef":$name, "Type":$type, 1100 CArg<"Linkage", "Linkage::External">:$linkage, 1101 CArg<"bool", "false">:$dsoLocal, 1102 CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs, 1103 CArg<"ArrayRef<DictionaryAttr>", "{}">:$argAttrs)> 1104 ]; 1105 1106 let extraClassDeclaration = [{ 1107 // Add an entry block to an empty function, and set up the block arguments 1108 // to match the signature of the function. 1109 Block *addEntryBlock(); 1110 1111 LLVMFunctionType getType() { 1112 return (*this)->getAttrOfType<TypeAttr>(getTypeAttrName()) 1113 .getValue().cast<LLVMFunctionType>(); 1114 } 1115 bool isVarArg() { 1116 return getType().isVarArg(); 1117 } 1118 1119 // Hook for OpTrait::FunctionLike, returns the number of function arguments`. 1120 // Depends on the type attribute being correct as checked by verifyType. 1121 unsigned getNumFuncArguments(); 1122 1123 // Hook for OpTrait::FunctionLike, returns the number of function results. 1124 // Depends on the type attribute being correct as checked by verifyType. 1125 unsigned getNumFuncResults(); 1126 1127 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1128 // attribute is present. This can check for preconditions of the 1129 // getNumArguments hook not failing. 1130 LogicalResult verifyType(); 1131 }]; 1132 1133 let verifier = [{ return ::verify(*this); }]; 1134 let printer = [{ printLLVMFuncOp(p, *this); }]; 1135 let parser = [{ return parseLLVMFuncOp(parser, result); }]; 1136} 1137 1138def LLVM_NullOp 1139 : LLVM_Op<"mlir.null", [NoSideEffect]>, 1140 LLVM_Builder<"$res = llvm::ConstantPointerNull::get(" 1141 " cast<llvm::PointerType>($_resultType));"> { 1142 let summary = "Defines a value containing a null pointer to LLVM type."; 1143 let description = [{ 1144 Unlike LLVM IR, MLIR does not have first-class null pointers. They must be 1145 explicitly created as SSA values using `llvm.mlir.null`. This operation has 1146 no operands or attributes, and returns a null value of a wrapped LLVM IR 1147 pointer type. 1148 1149 Examples: 1150 1151 ```mlir 1152 // Null pointer to i8. 1153 %0 = llvm.mlir.null : !llvm.ptr<i8> 1154 1155 // Null pointer to a function with signature void(). 1156 %1 = llvm.mlir.null : !llvm.ptr<func<void ()>> 1157 ``` 1158 }]; 1159 1160 let results = (outs LLVM_AnyPointer:$res); 1161 let builders = [LLVM_OneResultOpBuilder]; 1162 let assemblyFormat = "attr-dict `:` type($res)"; 1163} 1164 1165def LLVM_UndefOp : LLVM_Op<"mlir.undef", [NoSideEffect]>, 1166 LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> { 1167 let summary = "Creates an undefined value of LLVM dialect type."; 1168 let description = [{ 1169 Unlike LLVM IR, MLIR does not have first-class undefined values. Such values 1170 must be created as SSA values using `llvm.mlir.undef`. This operation has no 1171 operands or attributes. It creates an undefined value of the specified LLVM 1172 IR dialect type wrapping an LLVM IR structure type. 1173 1174 Example: 1175 1176 ```mlir 1177 // Create a structure with a 32-bit integer followed by a float. 1178 %0 = llvm.mlir.undef : !llvm.struct<(i32, f32)> 1179 ``` 1180 }]; 1181 let results = (outs LLVM_Type:$res); 1182 let builders = [LLVM_OneResultOpBuilder]; 1183 let assemblyFormat = "attr-dict `:` type($res)"; 1184} 1185 1186def LLVM_ConstantOp 1187 : LLVM_Op<"mlir.constant", [NoSideEffect]>, 1188 LLVM_Builder<[{$res = getLLVMConstant($_resultType, $value, $_location, 1189 moduleTranslation);}]> 1190{ 1191 let summary = "Defines a constant of LLVM type."; 1192 let description = [{ 1193 Unlike LLVM IR, MLIR does not have first-class constant values. Therefore, 1194 all constants must be created as SSA values before being used in other 1195 operations. `llvm.mlir.constant` creates such values for scalars and 1196 vectors. It has a mandatory `value` attribute, which may be an integer, 1197 floating point attribute; dense or sparse attribute containing integers or 1198 floats. The type of the attribute is one of the corresponding MLIR builtin 1199 types. It may be omitted for `i64` and `f64` types that are implied. The 1200 operation produces a new SSA value of the specified LLVM IR dialect type. 1201 The type of that value _must_ correspond to the attribute type converted to 1202 LLVM IR. 1203 1204 Examples: 1205 1206 ```mlir 1207 // Integer constant, internal i32 is mandatory 1208 %0 = llvm.mlir.constant(42 : i32) : i32 1209 1210 // It's okay to omit i64. 1211 %1 = llvm.mlir.constant(42) : i64 1212 1213 // Floating point constant. 1214 %2 = llvm.mlir.constant(42.0 : f32) : f32 1215 1216 // Splat dense vector constant. 1217 %3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : vector<4xf32> 1218 ``` 1219 }]; 1220 1221 let arguments = (ins AnyAttr:$value); 1222 let results = (outs LLVM_Type:$res); 1223 let builders = [LLVM_OneResultOpBuilder]; 1224 let assemblyFormat = "`(` $value `)` attr-dict `:` type($res)"; 1225 let verifier = [{ return ::verify(*this); }]; 1226} 1227 1228// Operations that correspond to LLVM intrinsics. With MLIR operation set being 1229// extendable, there is no reason to introduce a hard boundary between "core" 1230// operations and intrinsics. However, we systematically prefix them with 1231// "intr." to avoid potential name clashes. 1232 1233class LLVM_UnaryIntrinsicOp<string func, list<OpTrait> traits = []> : 1234 LLVM_OneResultIntrOp<func, [], [0], 1235 !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> { 1236 let arguments = (ins LLVM_Type:$in); 1237} 1238 1239class LLVM_BinarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> : 1240 LLVM_OneResultIntrOp<func, [], [0], 1241 !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> { 1242 let arguments = (ins LLVM_Type:$a, LLVM_Type:$b); 1243} 1244 1245class LLVM_TernarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> : 1246 LLVM_OneResultIntrOp<func, [], [0], 1247 !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> { 1248 let arguments = (ins LLVM_Type:$a, LLVM_Type:$b, LLVM_Type:$c); 1249} 1250 1251def LLVM_CopySignOp : LLVM_BinarySameArgsIntrinsicOp<"copysign">; 1252def LLVM_CosOp : LLVM_UnaryIntrinsicOp<"cos">; 1253def LLVM_ExpOp : LLVM_UnaryIntrinsicOp<"exp">; 1254def LLVM_Exp2Op : LLVM_UnaryIntrinsicOp<"exp2">; 1255def LLVM_FAbsOp : LLVM_UnaryIntrinsicOp<"fabs">; 1256def LLVM_FCeilOp : LLVM_UnaryIntrinsicOp<"ceil">; 1257def LLVM_FFloorOp : LLVM_UnaryIntrinsicOp<"floor">; 1258def LLVM_FMAOp : LLVM_TernarySameArgsIntrinsicOp<"fma">; 1259def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrinsicOp<"fmuladd">; 1260def LLVM_Log10Op : LLVM_UnaryIntrinsicOp<"log10">; 1261def LLVM_Log2Op : LLVM_UnaryIntrinsicOp<"log2">; 1262def LLVM_LogOp : LLVM_UnaryIntrinsicOp<"log">; 1263def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0]> { 1264 let arguments = (ins LLVM_Type:$addr, LLVM_Type:$rw, LLVM_Type:$hint, 1265 LLVM_Type:$cache); 1266} 1267def LLVM_SinOp : LLVM_UnaryIntrinsicOp<"sin">; 1268def LLVM_SqrtOp : LLVM_UnaryIntrinsicOp<"sqrt">; 1269def LLVM_PowOp : LLVM_BinarySameArgsIntrinsicOp<"pow">; 1270def LLVM_BitReverseOp : LLVM_UnaryIntrinsicOp<"bitreverse">; 1271def LLVM_CtPopOp : LLVM_UnaryIntrinsicOp<"ctpop">; 1272def LLVM_MaxNumOp : LLVM_BinarySameArgsIntrinsicOp<"maxnum">; 1273def LLVM_MinNumOp : LLVM_BinarySameArgsIntrinsicOp<"minnum">; 1274def LLVM_MaximumOp : LLVM_BinarySameArgsIntrinsicOp<"maximum">; 1275def LLVM_MinimumOp : LLVM_BinarySameArgsIntrinsicOp<"minimum">; 1276def LLVM_SMaxOp : LLVM_BinarySameArgsIntrinsicOp<"smax">; 1277def LLVM_SMinOp : LLVM_BinarySameArgsIntrinsicOp<"smin">; 1278 1279def LLVM_MemcpyOp : LLVM_ZeroResultIntrOp<"memcpy", [0, 1, 2]> { 1280 let arguments = (ins LLVM_Type:$dst, LLVM_Type:$src, LLVM_Type:$len, 1281 LLVM_Type:$isVolatile); 1282} 1283def LLVM_MemcpyInlineOp : LLVM_ZeroResultIntrOp<"memcpy.inline", [0, 1, 2]> { 1284 let arguments = (ins LLVM_Type:$dst, LLVM_Type:$src, LLVM_Type:$len, 1285 LLVM_Type:$isVolatile); 1286} 1287 1288// Intrinsics with multiple returns. 1289 1290def LLVM_SAddWithOverflowOp 1291 : LLVM_IntrOp<"sadd.with.overflow", [0], [], [], 2> { 1292 let arguments = (ins LLVM_Type, LLVM_Type); 1293} 1294def LLVM_UAddWithOverflowOp 1295 : LLVM_IntrOp<"uadd.with.overflow", [0], [], [], 2> { 1296 let arguments = (ins LLVM_Type, LLVM_Type); 1297} 1298def LLVM_SSubWithOverflowOp 1299 : LLVM_IntrOp<"ssub.with.overflow", [0], [], [], 2> { 1300 let arguments = (ins LLVM_Type, LLVM_Type); 1301} 1302def LLVM_USubWithOverflowOp 1303 : LLVM_IntrOp<"usub.with.overflow", [0], [], [], 2> { 1304 let arguments = (ins LLVM_Type, LLVM_Type); 1305} 1306def LLVM_SMulWithOverflowOp 1307 : LLVM_IntrOp<"smul.with.overflow", [0], [], [], 2> { 1308 let arguments = (ins LLVM_Type, LLVM_Type); 1309} 1310def LLVM_UMulWithOverflowOp 1311 : LLVM_IntrOp<"umul.with.overflow", [0], [], [], 2> { 1312 let arguments = (ins LLVM_Type, LLVM_Type); 1313} 1314 1315// 1316// Coroutine intrinsics. 1317// 1318 1319def LLVM_CoroIdOp : LLVM_IntrOp<"coro.id", [], [], [], 1> { 1320 let arguments = (ins I32:$align, 1321 LLVM_i8Ptr:$promise, 1322 LLVM_i8Ptr:$coroaddr, 1323 LLVM_i8Ptr:$fnaddrs); 1324 let assemblyFormat = "$align `,` $promise `,` $coroaddr `,` $fnaddrs" 1325 " attr-dict `:` type($res)"; 1326} 1327 1328def LLVM_CoroBeginOp : LLVM_IntrOp<"coro.begin", [], [], [], 1> { 1329 let arguments = (ins LLVM_TokenType:$token, 1330 LLVM_i8Ptr:$mem); 1331 let assemblyFormat = "$token `,` $mem attr-dict `:` type($res)"; 1332} 1333 1334def LLVM_CoroSizeOp : LLVM_IntrOp<"coro.size", [0], [], [], 1> { 1335 let assemblyFormat = "attr-dict `:` type($res)"; 1336} 1337 1338def LLVM_CoroSaveOp : LLVM_IntrOp<"coro.save", [], [], [], 1> { 1339 let arguments = (ins LLVM_i8Ptr:$handle); 1340 let assemblyFormat = "$handle attr-dict `:` type($res)"; 1341} 1342 1343def LLVM_CoroSuspendOp : LLVM_IntrOp<"coro.suspend", [], [], [], 1> { 1344 let arguments = (ins LLVM_TokenType:$save, 1345 I1:$final); 1346 let assemblyFormat = "$save `,` $final attr-dict `:` type($res)"; 1347} 1348 1349def LLVM_CoroEndOp : LLVM_IntrOp<"coro.end", [], [], [], 1> { 1350 let arguments = (ins LLVM_i8Ptr:$handle, 1351 I1:$unwind); 1352 let assemblyFormat = "$handle `,` $unwind attr-dict `:` type($res)"; 1353} 1354 1355def LLVM_CoroFreeOp : LLVM_IntrOp<"coro.free", [], [], [], 1> { 1356 let arguments = (ins LLVM_TokenType:$id, 1357 LLVM_i8Ptr:$handle); 1358 let assemblyFormat = "$id `,` $handle attr-dict `:` type($res)"; 1359} 1360 1361def LLVM_CoroResumeOp : LLVM_IntrOp<"coro.resume", [], [], [], 0> { 1362 let arguments = (ins LLVM_i8Ptr:$handle); 1363 let assemblyFormat = "$handle attr-dict"; 1364} 1365 1366// 1367// Stack save/restore intrinsics. 1368// 1369 1370def LLVM_StackSaveOp : LLVM_OneResultIntrOp<"stacksave"> { 1371 let assemblyFormat = "attr-dict `:` type($res)"; 1372} 1373 1374def LLVM_StackRestoreOp : LLVM_ZeroResultIntrOp<"stackrestore"> { 1375 let arguments = (ins LLVM_i8Ptr:$ptr); 1376 let assemblyFormat = "$ptr attr-dict"; 1377} 1378 1379// 1380// Vector Reductions. 1381// 1382 1383def LLVM_vector_reduce_add : LLVM_VectorReduction<"add">; 1384def LLVM_vector_reduce_and : LLVM_VectorReduction<"and">; 1385def LLVM_vector_reduce_mul : LLVM_VectorReduction<"mul">; 1386def LLVM_vector_reduce_fmax : LLVM_VectorReduction<"fmax">; 1387def LLVM_vector_reduce_fmin : LLVM_VectorReduction<"fmin">; 1388def LLVM_vector_reduce_or : LLVM_VectorReduction<"or">; 1389def LLVM_vector_reduce_smax : LLVM_VectorReduction<"smax">; 1390def LLVM_vector_reduce_smin : LLVM_VectorReduction<"smin">; 1391def LLVM_vector_reduce_umax : LLVM_VectorReduction<"umax">; 1392def LLVM_vector_reduce_umin : LLVM_VectorReduction<"umin">; 1393def LLVM_vector_reduce_xor : LLVM_VectorReduction<"xor">; 1394 1395def LLVM_vector_reduce_fadd : LLVM_VectorReductionAcc<"fadd">; 1396def LLVM_vector_reduce_fmul : LLVM_VectorReductionAcc<"fmul">; 1397 1398// 1399// LLVM Matrix operations. 1400// 1401 1402/// Create a column major, strided 2-D matrix load, as specified in the LLVM 1403/// MatrixBuilder. 1404/// data - Start address of the matrix read 1405/// rows - Number of rows in matrix (must be a constant) 1406/// isVolatile - True if the load operation is marked as volatile. 1407/// columns - Number of columns in matrix (must be a constant) 1408/// stride - Space between columns 1409def LLVM_MatrixColumnMajorLoadOp : LLVM_Op<"intr.matrix.column.major.load"> { 1410 let arguments = (ins LLVM_Type:$data, LLVM_Type:$stride, I1Attr:$isVolatile, 1411 I32Attr:$rows, I32Attr:$columns); 1412 let results = (outs LLVM_Type:$res); 1413 let builders = [LLVM_OneResultOpBuilder]; 1414 string llvmBuilder = [{ 1415 llvm::MatrixBuilder<decltype(builder)> mb(builder); 1416 const llvm::DataLayout &dl = 1417 builder.GetInsertBlock()->getModule()->getDataLayout(); 1418 llvm::Align align = dl.getABITypeAlign( 1419 $data->getType()->getPointerElementType()); 1420 $res = mb.CreateColumnMajorLoad( 1421 $data, align, $stride, $isVolatile, $rows, 1422 $columns); 1423 }]; 1424 let assemblyFormat = "$data `,` `<` `stride` `=` $stride `>` attr-dict" 1425 "`:` type($res) `from` type($data) `stride` type($stride)"; 1426} 1427 1428/// Create a column major, strided 2-D matrix store, as specified in the LLVM 1429/// MatrixBuilder. 1430/// matrix - Matrix to store 1431/// ptr - Pointer to write back to 1432/// isVolatile - True if the load operation is marked as volatile. 1433/// rows - Number of rows in matrix (must be a constant) 1434/// columns - Number of columns in matrix (must be a constant) 1435/// stride - Space between columns 1436def LLVM_MatrixColumnMajorStoreOp : LLVM_Op<"intr.matrix.column.major.store"> { 1437 let arguments = (ins LLVM_Type:$matrix, LLVM_Type:$data, LLVM_Type:$stride, 1438 I1Attr:$isVolatile, I32Attr:$rows, I32Attr:$columns); 1439 let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder]; 1440 string llvmBuilder = [{ 1441 llvm::MatrixBuilder<decltype(builder)> mb(builder); 1442 const llvm::DataLayout &dl = 1443 builder.GetInsertBlock()->getModule()->getDataLayout(); 1444 llvm::Align align = dl.getABITypeAlign( 1445 $data->getType()->getPointerElementType()); 1446 mb.CreateColumnMajorStore( 1447 $matrix, $data, align, $stride, $isVolatile, 1448 $rows, $columns); 1449 }]; 1450 let assemblyFormat = "$matrix `,` $data `,` `<` `stride` `=` $stride `>` " 1451 "attr-dict`:` type($matrix) `to` type($data) `stride` type($stride)"; 1452} 1453 1454/// Create a llvm.matrix.multiply call, multiplying 2-D matrices LHS and RHS, as 1455/// specified in the LLVM MatrixBuilder. 1456def LLVM_MatrixMultiplyOp : LLVM_Op<"intr.matrix.multiply"> { 1457 let arguments = (ins LLVM_Type:$lhs, LLVM_Type:$rhs, I32Attr:$lhs_rows, 1458 I32Attr:$lhs_columns, I32Attr:$rhs_columns); 1459 let results = (outs LLVM_Type:$res); 1460 let builders = [LLVM_OneResultOpBuilder]; 1461 string llvmBuilder = [{ 1462 llvm::MatrixBuilder<decltype(builder)> mb(builder); 1463 $res = mb.CreateMatrixMultiply( 1464 $lhs, $rhs, $lhs_rows, $lhs_columns, 1465 $rhs_columns); 1466 }]; 1467 let assemblyFormat = "$lhs `,` $rhs attr-dict " 1468 "`:` `(` type($lhs) `,` type($rhs) `)` `->` type($res)"; 1469} 1470 1471/// Create a llvm.matrix.transpose call, transposing a `rows` x `columns` 2-D 1472/// `matrix`, as specified in the LLVM MatrixBuilder. 1473def LLVM_MatrixTransposeOp : LLVM_Op<"intr.matrix.transpose"> { 1474 let arguments = (ins LLVM_Type:$matrix, I32Attr:$rows, I32Attr:$columns); 1475 let results = (outs LLVM_Type:$res); 1476 let builders = [LLVM_OneResultOpBuilder]; 1477 string llvmBuilder = [{ 1478 llvm::MatrixBuilder<decltype(builder)> mb(builder); 1479 $res = mb.CreateMatrixTranspose( 1480 $matrix, $rows, $columns); 1481 }]; 1482 let assemblyFormat = "$matrix attr-dict `:` type($matrix) `into` type($res)"; 1483} 1484 1485// 1486// LLVM masked operations. 1487// 1488 1489/// Create a llvm.get.active.lane.mask to set a mask up to a given position. 1490def LLVM_GetActiveLaneMaskOp 1491 : LLVM_OneResultIntrOp<"get.active.lane.mask", [0], [0], [NoSideEffect]> { 1492 let arguments = (ins LLVM_Type:$base, LLVM_Type:$n); 1493 let assemblyFormat = "$base `,` $n attr-dict `:` " 1494 "type($base) `,` type($n) `to` type($res)"; 1495} 1496 1497/// Create a call to Masked Load intrinsic. 1498def LLVM_MaskedLoadOp : LLVM_Op<"intr.masked.load"> { 1499 let arguments = (ins LLVM_Type:$data, LLVM_Type:$mask, 1500 Variadic<LLVM_Type>:$pass_thru, I32Attr:$alignment); 1501 let results = (outs LLVM_Type:$res); 1502 let builders = [LLVM_OneResultOpBuilder]; 1503 string llvmBuilder = [{ 1504 llvm::Type *Ty = $data->getType()->getPointerElementType(); 1505 $res = $pass_thru.empty() ? builder.CreateMaskedLoad( 1506 Ty, $data, llvm::Align($alignment), $mask) : 1507 builder.CreateMaskedLoad( 1508 Ty, $data, llvm::Align($alignment), $mask, $pass_thru[0]); 1509 }]; 1510 let assemblyFormat = 1511 "operands attr-dict `:` functional-type(operands, results)"; 1512} 1513 1514/// Create a call to Masked Store intrinsic. 1515def LLVM_MaskedStoreOp : LLVM_Op<"intr.masked.store"> { 1516 let arguments = (ins LLVM_Type:$value, LLVM_Type:$data, LLVM_Type:$mask, 1517 I32Attr:$alignment); 1518 let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder]; 1519 string llvmBuilder = [{ 1520 builder.CreateMaskedStore( 1521 $value, $data, llvm::Align($alignment), $mask); 1522 }]; 1523 let assemblyFormat = "$value `,` $data `,` $mask attr-dict `:` " 1524 "type($value) `,` type($mask) `into` type($data)"; 1525} 1526 1527/// Create a call to Masked Gather intrinsic. 1528def LLVM_masked_gather : LLVM_Op<"intr.masked.gather"> { 1529 let arguments = (ins LLVM_Type:$ptrs, LLVM_Type:$mask, 1530 Variadic<LLVM_Type>:$pass_thru, I32Attr:$alignment); 1531 let results = (outs LLVM_Type:$res); 1532 let builders = [LLVM_OneResultOpBuilder]; 1533 string llvmBuilder = [{ 1534 llvm::VectorType *PtrVecTy = cast<llvm::VectorType>($ptrs->getType()); 1535 llvm::Type *Ty = llvm::VectorType::get( 1536 PtrVecTy->getElementType()->getPointerElementType(), 1537 PtrVecTy->getElementCount()); 1538 $res = $pass_thru.empty() ? builder.CreateMaskedGather( 1539 Ty, $ptrs, llvm::Align($alignment), $mask) : 1540 builder.CreateMaskedGather( 1541 Ty, $ptrs, llvm::Align($alignment), $mask, $pass_thru[0]); 1542 }]; 1543 let assemblyFormat = 1544 "operands attr-dict `:` functional-type(operands, results)"; 1545} 1546 1547/// Create a call to Masked Scatter intrinsic. 1548def LLVM_masked_scatter : LLVM_Op<"intr.masked.scatter"> { 1549 let arguments = (ins LLVM_Type:$value, LLVM_Type:$ptrs, LLVM_Type:$mask, 1550 I32Attr:$alignment); 1551 let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder]; 1552 string llvmBuilder = [{ 1553 builder.CreateMaskedScatter( 1554 $value, $ptrs, llvm::Align($alignment), $mask); 1555 }]; 1556 let assemblyFormat = "$value `,` $ptrs `,` $mask attr-dict `:` " 1557 "type($value) `,` type($mask) `into` type($ptrs)"; 1558} 1559 1560/// Create a call to Masked Expand Load intrinsic. 1561def LLVM_masked_expandload : LLVM_IntrOp<"masked.expandload", [0], [], [], 1> { 1562 let arguments = (ins LLVM_Type, LLVM_Type, LLVM_Type); 1563} 1564 1565/// Create a call to Masked Compress Store intrinsic. 1566def LLVM_masked_compressstore 1567 : LLVM_IntrOp<"masked.compressstore", [], [0], [], 0> { 1568 let arguments = (ins LLVM_Type, LLVM_Type, LLVM_Type); 1569} 1570 1571// 1572// Atomic operations. 1573// 1574 1575def AtomicBinOpXchg : I64EnumAttrCase<"xchg", 0>; 1576def AtomicBinOpAdd : I64EnumAttrCase<"add", 1>; 1577def AtomicBinOpSub : I64EnumAttrCase<"sub", 2>; 1578def AtomicBinOpAnd : I64EnumAttrCase<"_and", 3>; 1579def AtomicBinOpNand : I64EnumAttrCase<"nand", 4>; 1580def AtomicBinOpOr : I64EnumAttrCase<"_or", 5>; 1581def AtomicBinOpXor : I64EnumAttrCase<"_xor", 6>; 1582def AtomicBinOpMax : I64EnumAttrCase<"max", 7>; 1583def AtomicBinOpMin : I64EnumAttrCase<"min", 8>; 1584def AtomicBinOpUMax : I64EnumAttrCase<"umax", 9>; 1585def AtomicBinOpUMin : I64EnumAttrCase<"umin", 10>; 1586def AtomicBinOpFAdd : I64EnumAttrCase<"fadd", 11>; 1587def AtomicBinOpFSub : I64EnumAttrCase<"fsub", 12>; 1588def AtomicBinOp : I64EnumAttr< 1589 "AtomicBinOp", 1590 "llvm.atomicrmw binary operations", 1591 [AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd, 1592 AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax, 1593 AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd, 1594 AtomicBinOpFSub]> { 1595 let cppNamespace = "::mlir::LLVM"; 1596} 1597 1598def AtomicOrderingNotAtomic : I64EnumAttrCase<"not_atomic", 0>; 1599def AtomicOrderingUnordered : I64EnumAttrCase<"unordered", 1>; 1600def AtomicOrderingMonotonic : I64EnumAttrCase<"monotonic", 2>; 1601def AtomicOrderingAcquire : I64EnumAttrCase<"acquire", 4>; 1602def AtomicOrderingRelease : I64EnumAttrCase<"release", 5>; 1603def AtomicOrderingAcquireRelease : I64EnumAttrCase<"acq_rel", 6>; 1604def AtomicOrderingSequentiallyConsistent : I64EnumAttrCase<"seq_cst", 7>; 1605def AtomicOrdering : I64EnumAttr< 1606 "AtomicOrdering", 1607 "Atomic ordering for LLVM's memory model", 1608 [AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic, 1609 AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcquireRelease, 1610 AtomicOrderingSequentiallyConsistent]> { 1611 let cppNamespace = "::mlir::LLVM"; 1612} 1613 1614def LLVM_AtomicRMWType : AnyTypeOf<[LLVM_AnyFloat, AnyInteger]>; 1615 1616// FIXME: Need to add alignment attribute to MLIR atomicrmw operation. 1617def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw"> { 1618 let arguments = (ins AtomicBinOp:$bin_op, 1619 LLVM_PointerTo<LLVM_AtomicRMWType>:$ptr, 1620 LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering); 1621 let results = (outs LLVM_AtomicRMWType:$res); 1622 let llvmBuilder = [{ 1623 $res = builder.CreateAtomicRMW(getLLVMAtomicBinOp($bin_op), $ptr, $val, 1624 llvm::MaybeAlign(), 1625 getLLVMAtomicOrdering($ordering)); 1626 }]; 1627 let parser = [{ return parseAtomicRMWOp(parser, result); }]; 1628 let printer = [{ printAtomicRMWOp(p, *this); }]; 1629 let verifier = "return ::verify(*this);"; 1630} 1631 1632def LLVM_AtomicCmpXchgType : AnyTypeOf<[AnyInteger, LLVM_AnyPointer]>; 1633def LLVM_AtomicCmpXchgResultType : Type<And<[ 1634 LLVM_AnyStruct.predicate, 1635 CPred<"$_self.cast<::mlir::LLVM::LLVMStructType>().getBody().size() == 2">, 1636 SubstLeaves<"$_self", 1637 "$_self.cast<::mlir::LLVM::LLVMStructType>().getBody()[0]", 1638 LLVM_AtomicCmpXchgType.predicate>, 1639 SubstLeaves<"$_self", 1640 "$_self.cast<::mlir::LLVM::LLVMStructType>().getBody()[1]", 1641 I1.predicate>]>, 1642 "an LLVM struct type with any integer or pointer followed by a single-bit " 1643 "integer">; 1644 1645// FIXME: Need to add alignment attribute to MLIR cmpxchg operation. 1646def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg"> { 1647 let arguments = (ins LLVM_PointerTo<LLVM_AtomicCmpXchgType>:$ptr, 1648 LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val, 1649 AtomicOrdering:$success_ordering, 1650 AtomicOrdering:$failure_ordering); 1651 let results = (outs LLVM_AtomicCmpXchgResultType:$res); 1652 let llvmBuilder = [{ 1653 $res = builder.CreateAtomicCmpXchg($ptr, $cmp, $val, llvm::MaybeAlign(), 1654 getLLVMAtomicOrdering($success_ordering), 1655 getLLVMAtomicOrdering($failure_ordering)); 1656 }]; 1657 let parser = [{ return parseAtomicCmpXchgOp(parser, result); }]; 1658 let printer = [{ printAtomicCmpXchgOp(p, *this); }]; 1659 let verifier = "return ::verify(*this);"; 1660} 1661 1662def LLVM_AssumeOp : LLVM_Op<"intr.assume", []> { 1663 let arguments = (ins LLVM_Type:$cond); 1664 let llvmBuilder = [{ 1665 llvm::Module *module = builder.GetInsertBlock()->getModule(); 1666 llvm::Function *fn = 1667 llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::assume, {}); 1668 builder.CreateCall(fn, {$cond}); 1669 }]; 1670} 1671 1672def LLVM_FenceOp : LLVM_Op<"fence"> { 1673 let arguments = (ins AtomicOrdering:$ordering, StrAttr:$syncscope); 1674 let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder]; 1675 let llvmBuilder = [{ 1676 llvm::LLVMContext &llvmContext = builder.getContext(); 1677 builder.CreateFence(getLLVMAtomicOrdering($ordering), 1678 llvmContext.getOrInsertSyncScopeID($syncscope)); 1679 }]; 1680 let parser = [{ return parseFenceOp(parser, result); }]; 1681 let printer = [{ printFenceOp(p, *this); }]; 1682 let verifier = "return ::verify(*this);"; 1683} 1684 1685def AsmATT : LLVM_EnumAttrCase< 1686 /*string cppSym=*/"AD_ATT", /*string irSym=*/"att", 1687 /*string llvmSym=*/"AD_ATT", /*int val=*/0>; 1688def AsmIntel : LLVM_EnumAttrCase< 1689 /*string cppSym=*/"AD_Intel", /*string irSym=*/"intel", 1690 /*string llvmSym=*/"AD_Intel", /*int val=*/1>; 1691def AsmATTOrIntel : LLVM_EnumAttr< 1692 /*string name=*/"AsmDialect", 1693 /*string llvmName=*/"::llvm::InlineAsm::AsmDialect", 1694 /*string description=*/"ATT (0) or Intel (1) asm dialect", 1695 /*list<LLVM_EnumAttrCase> cases=*/[AsmATT, AsmIntel]> { 1696 let cppNamespace = "::mlir::LLVM"; 1697} 1698 1699def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", []> { 1700 let description = [{ 1701 The InlineAsmOp mirrors the underlying LLVM semantics with a notable 1702 exception: the embedded `asm_string` is not allowed to define or reference 1703 any symbol or any global variable: only the operands of the op may be read, 1704 written, or referenced. 1705 Attempting to define or reference any symbol or any global behavior is 1706 considered undefined behavior at this time. 1707 }]; 1708 let arguments = ( 1709 ins Variadic<LLVM_Type>:$operands, 1710 StrAttr:$asm_string, 1711 StrAttr:$constraints, 1712 UnitAttr:$has_side_effects, 1713 UnitAttr:$is_align_stack, 1714 OptionalAttr< 1715 DefaultValuedAttr<AsmATTOrIntel, "AsmDialect::AD_ATT">>:$asm_dialect); 1716 1717 let results = (outs Optional<LLVM_Type>:$res); 1718 1719 let assemblyFormat = [{ 1720 (`has_side_effects` $has_side_effects^)? 1721 (`is_align_stack` $is_align_stack^)? 1722 (`asm_dialect` `=` $asm_dialect^)? 1723 attr-dict 1724 $asm_string `,` $constraints 1725 operands `:` functional-type(operands, results) 1726 }]; 1727} 1728#endif // LLVMIR_OPS 1729