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