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