075df4938b90111ea83702ff9c0d7416757f86c4
[lldb.git] / mlir / include / mlir / Dialect / LLVMIR / LLVMOps.td
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
16 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
17 include "mlir/IR/SymbolInterfaces.td"
18 include "mlir/Interfaces/ControlFlowInterfaces.td"
19 include "mlir/Interfaces/SideEffectInterfaces.td"
20
21 class LLVM_Builder<string builder> {
22   string llvmBuilder = builder;
23 }
24
25 def LLVM_OneResultOpBuilder :
26   OpBuilderDAG<(ins "Type":$resultType, "ValueRange":$operands,
27     CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes),
28   [{
29     if (resultType) $_state.addTypes(resultType);
30     $_state.addOperands(operands);
31     for (auto namedAttr : attributes) {
32       $_state.addAttribute(namedAttr.first, namedAttr.second);
33     }
34   }]>;
35
36 def LLVM_ZeroResultOpBuilder :
37   OpBuilderDAG<(ins "ValueRange":$operands,
38     CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes),
39   [{
40     $_state.addOperands(operands);
41     for (auto namedAttr : attributes) {
42       $_state.addAttribute(namedAttr.first, namedAttr.second);
43     }
44   }]>;
45
46 class LLVM_TwoBuilders<OpBuilderDAG b1, OpBuilderDAG b2> {
47   list<OpBuilderDAG> builders = [b1, b2];
48 }
49
50 // Base class for LLVM operations with one result.
51 class LLVM_OneResultOp<string mnemonic, list<OpTrait> traits = []> :
52     LLVM_Op<mnemonic, traits>, Results<(outs LLVM_Type:$res)> {
53   let builders = [LLVM_OneResultOpBuilder];
54 }
55
56 // Compatibility builder that takes an instance of wrapped llvm::VoidType
57 // to indicate no result.
58 def LLVM_VoidResultTypeOpBuilder :
59   OpBuilderDAG<(ins "Type":$resultType, "ValueRange":$operands,
60     CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes),
61   [{
62     auto llvmType = resultType.dyn_cast<LLVMType>(); (void)llvmType;
63     assert(llvmType && "result must be an LLVM type");
64     assert(llvmType.isVoidTy() &&
65            "for zero-result operands, only 'void' is accepted as result type");
66     build($_builder, $_state, operands, attributes);
67   }]>;
68
69 // Base class for LLVM operations with zero results.
70 class LLVM_ZeroResultOp<string mnemonic, list<OpTrait> traits = []> :
71     LLVM_Op<mnemonic, traits>, Results<(outs)>,
72     LLVM_TwoBuilders<LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder>;
73
74 // Opaque builder used for terminator operations that contain successors.
75 def LLVM_TerminatorPassthroughOpBuilder :
76   OpBuilderDAG<(ins "ValueRange":$operands, "SuccessorRange":$destinations,
77     CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes),
78   [{
79     $_state.addOperands(operands);
80     $_state.addSuccessors(destinations);
81     $_state.addAttributes(attributes);
82   }]>;
83
84 // Base class for LLVM terminator operations.  All terminator operations have
85 // zero results and an optional list of successors.
86 class LLVM_TerminatorOp<string mnemonic, list<OpTrait> traits = []> :
87     LLVM_Op<mnemonic, !listconcat(traits, [Terminator])>;
88
89 // Class for arithmetic binary operations.
90 class LLVM_ArithmeticOpBase<Type type, string mnemonic,
91                             string builderFunc, list<OpTrait> traits = []> :
92     LLVM_OneResultOp<mnemonic,
93            !listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
94     LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> {
95   let arguments = (ins LLVM_ScalarOrVectorOf<type>:$lhs,
96                    LLVM_ScalarOrVectorOf<type>:$rhs);
97   let parser =
98       [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }];
99   let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }];
100 }
101 class LLVM_IntArithmeticOp<string mnemonic, string builderFunc,
102                            list<OpTrait> traits = []> :
103     LLVM_ArithmeticOpBase<LLVM_AnyInteger, mnemonic, builderFunc, traits>;
104 class LLVM_FloatArithmeticOp<string mnemonic, string builderFunc,
105                              list<OpTrait> traits = []> :
106     LLVM_ArithmeticOpBase<LLVM_AnyFloat, mnemonic, builderFunc, traits>;
107
108 // Class for arithmetic unary operations.
109 class LLVM_UnaryArithmeticOp<Type type, string mnemonic,
110                              string builderFunc, list<OpTrait> traits = []> :
111     LLVM_OneResultOp<mnemonic,
112            !listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
113     LLVM_Builder<"$res = builder." # builderFunc # "($operand);"> {
114   let arguments = (ins type:$operand);
115   let parser =
116       [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }];
117   let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }];
118 }
119
120 // Integer binary operations.
121 def LLVM_AddOp : LLVM_IntArithmeticOp<"add", "CreateAdd", [Commutative]>;
122 def LLVM_SubOp : LLVM_IntArithmeticOp<"sub", "CreateSub">;
123 def LLVM_MulOp : LLVM_IntArithmeticOp<"mul", "CreateMul", [Commutative]>;
124 def LLVM_UDivOp : LLVM_IntArithmeticOp<"udiv", "CreateUDiv">;
125 def LLVM_SDivOp : LLVM_IntArithmeticOp<"sdiv", "CreateSDiv">;
126 def LLVM_URemOp : LLVM_IntArithmeticOp<"urem", "CreateURem">;
127 def LLVM_SRemOp : LLVM_IntArithmeticOp<"srem", "CreateSRem">;
128 def LLVM_AndOp : LLVM_IntArithmeticOp<"and", "CreateAnd">;
129 def LLVM_OrOp : LLVM_IntArithmeticOp<"or", "CreateOr">;
130 def LLVM_XOrOp : LLVM_IntArithmeticOp<"xor", "CreateXor">;
131 def LLVM_ShlOp : LLVM_IntArithmeticOp<"shl", "CreateShl">;
132 def LLVM_LShrOp : LLVM_IntArithmeticOp<"lshr", "CreateLShr">;
133 def LLVM_AShrOp : LLVM_IntArithmeticOp<"ashr", "CreateAShr">;
134
135 // Predicate for integer comparisons.
136 def ICmpPredicateEQ  : I64EnumAttrCase<"eq", 0>;
137 def ICmpPredicateNE  : I64EnumAttrCase<"ne", 1>;
138 def ICmpPredicateSLT : I64EnumAttrCase<"slt", 2>;
139 def ICmpPredicateSLE : I64EnumAttrCase<"sle", 3>;
140 def ICmpPredicateSGT : I64EnumAttrCase<"sgt", 4>;
141 def ICmpPredicateSGE : I64EnumAttrCase<"sge", 5>;
142 def ICmpPredicateULT : I64EnumAttrCase<"ult", 6>;
143 def ICmpPredicateULE : I64EnumAttrCase<"ule", 7>;
144 def ICmpPredicateUGT : I64EnumAttrCase<"ugt", 8>;
145 def ICmpPredicateUGE : I64EnumAttrCase<"uge", 9>;
146 def ICmpPredicate : I64EnumAttr<
147     "ICmpPredicate",
148     "llvm.icmp comparison predicate",
149     [ICmpPredicateEQ, ICmpPredicateNE, ICmpPredicateSLT, ICmpPredicateSLE,
150      ICmpPredicateSGT, ICmpPredicateSGE, ICmpPredicateULT, ICmpPredicateULE,
151      ICmpPredicateUGT, ICmpPredicateUGE]> {
152   let cppNamespace = "::mlir::LLVM";
153 }
154
155 // Other integer operations.
156 def LLVM_ICmpOp : LLVM_OneResultOp<"icmp", [NoSideEffect]> {
157   let arguments = (ins ICmpPredicate:$predicate,
158                    LLVM_ScalarOrVectorOf<LLVM_AnyInteger>:$lhs,
159                    LLVM_ScalarOrVectorOf<LLVM_AnyInteger>:$rhs);
160   let llvmBuilder = [{
161     $res = builder.CreateICmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
162   }];
163   let builders = [
164     OpBuilderDAG<(ins "ICmpPredicate":$predicate, "Value":$lhs, "Value":$rhs),
165     [{
166       build($_builder, $_state, LLVMType::getInt1Ty(lhs.getType().getContext()),
167             $_builder.getI64IntegerAttr(static_cast<int64_t>(predicate)), lhs, rhs);
168     }]>];
169   let parser = [{ return parseCmpOp<ICmpPredicate>(parser, result); }];
170   let printer = [{ printICmpOp(p, *this); }];
171 }
172
173 // Predicate for float comparisons
174 def FCmpPredicateFALSE  : I64EnumAttrCase<"_false", 0>;
175 def FCmpPredicateOEQ    : I64EnumAttrCase<"oeq", 1>;
176 def FCmpPredicateOGT    : I64EnumAttrCase<"ogt", 2>;
177 def FCmpPredicateOGE    : I64EnumAttrCase<"oge", 3>;
178 def FCmpPredicateOLT    : I64EnumAttrCase<"olt", 4>;
179 def FCmpPredicateOLE    : I64EnumAttrCase<"ole", 5>;
180 def FCmpPredicateONE    : I64EnumAttrCase<"one", 6>;
181 def FCmpPredicateORD    : I64EnumAttrCase<"ord", 7>;
182 def FCmpPredicateUEQ    : I64EnumAttrCase<"ueq", 8>;
183 def FCmpPredicateUGT    : I64EnumAttrCase<"ugt", 9>;
184 def FCmpPredicateUGE    : I64EnumAttrCase<"uge", 10>;
185 def FCmpPredicateULT    : I64EnumAttrCase<"ult", 11>;
186 def FCmpPredicateULE    : I64EnumAttrCase<"ule", 12>;
187 def FCmpPredicateUNE    : I64EnumAttrCase<"une", 13>;
188 def FCmpPredicateUNO    : I64EnumAttrCase<"uno", 14>;
189 def FCmpPredicateTRUE   : I64EnumAttrCase<"_true", 15>;
190
191 def FCmpPredicate : I64EnumAttr<
192     "FCmpPredicate",
193     "llvm.fcmp comparison predicate",
194     [FCmpPredicateFALSE, FCmpPredicateOEQ, FCmpPredicateOGT, FCmpPredicateOGE,
195      FCmpPredicateOLT, FCmpPredicateOLE, FCmpPredicateONE, FCmpPredicateORD,
196      FCmpPredicateUEQ, FCmpPredicateUGT, FCmpPredicateUGE, FCmpPredicateULT,
197      FCmpPredicateULE, FCmpPredicateUNE, FCmpPredicateUNO, FCmpPredicateTRUE
198     ]> {
199   let cppNamespace = "::mlir::LLVM";
200 }
201
202 // Other integer operations.
203 def LLVM_FCmpOp : LLVM_OneResultOp<"fcmp", [NoSideEffect]> {
204   let arguments = (ins FCmpPredicate:$predicate,
205                    LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$lhs,
206                    LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$rhs);
207   let llvmBuilder = [{
208     $res = builder.CreateFCmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
209   }];
210   let builders = [
211     OpBuilderDAG<(ins "FCmpPredicate":$predicate, "Value":$lhs, "Value":$rhs),
212     [{
213       build($_builder, $_state, LLVMType::getInt1Ty(lhs.getType().getContext()),
214             $_builder.getI64IntegerAttr(static_cast<int64_t>(predicate)), lhs, rhs);
215     }]>];
216   let parser = [{ return parseCmpOp<FCmpPredicate>(parser, result); }];
217   let printer = [{ printFCmpOp(p, *this); }];
218 }
219
220 // Floating point binary operations.
221 def LLVM_FAddOp : LLVM_FloatArithmeticOp<"fadd", "CreateFAdd">;
222 def LLVM_FSubOp : LLVM_FloatArithmeticOp<"fsub", "CreateFSub">;
223 def LLVM_FMulOp : LLVM_FloatArithmeticOp<"fmul", "CreateFMul">;
224 def LLVM_FDivOp : LLVM_FloatArithmeticOp<"fdiv", "CreateFDiv">;
225 def LLVM_FRemOp : LLVM_FloatArithmeticOp<"frem", "CreateFRem">;
226 def LLVM_FNegOp : LLVM_UnaryArithmeticOp<LLVM_ScalarOrVectorOf<LLVM_AnyFloat>,
227                                          "fneg", "CreateFNeg">;
228
229 // Common code definition that is used to verify and set the alignment attribute
230 // of LLVM ops that accept such an attribute.
231 class MemoryOpWithAlignmentBase {
232   code setAlignmentCode = [{
233     if ($alignment.hasValue()) {
234       auto align = $alignment.getValue();
235       if (align != 0)
236         inst->setAlignment(llvm::Align(align));
237     }
238   }];
239 }
240
241 // Code definition that is used for nontemporal metadata creation.
242 class MemoryOpWithAlignmentAndAttributes : MemoryOpWithAlignmentBase {
243   code setNonTemporalMetadataCode = [{
244     if ($nontemporal) {
245       llvm::Module *module = builder.GetInsertBlock()->getModule();
246       llvm::MDNode *metadata = llvm::MDNode::get(
247           inst->getContext(), llvm::ConstantAsMetadata::get(
248               builder.getInt32(1)));
249       inst->setMetadata(module->getMDKindID("nontemporal"), metadata);
250     }
251   }];
252 }
253
254 // Memory-related operations.
255 def LLVM_AllocaOp :
256     MemoryOpWithAlignmentBase,
257     LLVM_OneResultOp<"alloca"> {
258   let arguments = (ins LLVM_AnyInteger:$arraySize,
259                    OptionalAttr<I64Attr>:$alignment);
260   string llvmBuilder = [{
261     auto *inst = builder.CreateAlloca(
262       $_resultType->getPointerElementType(), $arraySize);
263     }] # setAlignmentCode # [{
264     $res = inst;
265   }];
266   let builders = [
267     OpBuilderDAG<(ins "Type":$resultType, "Value":$arraySize,
268       "unsigned":$alignment),
269     [{
270       if (alignment == 0)
271         return build($_builder, $_state, resultType, arraySize, IntegerAttr());
272       build($_builder, $_state, resultType, arraySize,
273         $_builder.getI64IntegerAttr(alignment));
274   }]>];
275   let parser = [{ return parseAllocaOp(parser, result); }];
276   let printer = [{ printAllocaOp(p, *this); }];
277 }
278
279 def LLVM_GEPOp : LLVM_OneResultOp<"getelementptr", [NoSideEffect]>,
280                  LLVM_Builder<"$res = builder.CreateGEP($base, $indices);"> {
281   let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_AnyPointer>:$base,
282                    Variadic<LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>:$indices);
283   let assemblyFormat = [{
284     $base `[` $indices `]` attr-dict `:` functional-type(operands, results)
285   }];
286 }
287
288 def LLVM_LoadOp :
289     MemoryOpWithAlignmentAndAttributes,
290     LLVM_OneResultOp<"load"> {
291   let arguments = (ins LLVM_PointerTo<LLVM_LoadableType>:$addr,
292                    OptionalAttr<I64Attr>:$alignment, UnitAttr:$volatile_,
293                    UnitAttr:$nontemporal);
294   string llvmBuilder = [{
295     auto *inst = builder.CreateLoad($addr, $volatile_);
296   }] # setAlignmentCode # setNonTemporalMetadataCode # [{
297     $res = inst;
298   }];
299   let builders = [
300     OpBuilderDAG<(ins "Value":$addr, CArg<"unsigned", "0">:$alignment,
301       CArg<"bool", "false">:$isVolatile, CArg<"bool", "false">:$isNonTemporal),
302     [{
303       auto type = addr.getType().cast<LLVMType>().getPointerElementTy();
304       build($_builder, $_state, type, addr, alignment, isVolatile, isNonTemporal);
305     }]>,
306     OpBuilderDAG<(ins "Type":$t, "Value":$addr,
307       CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
308       CArg<"bool", "false">:$isNonTemporal)>];
309   let parser = [{ return parseLoadOp(parser, result); }];
310   let printer = [{ printLoadOp(p, *this); }];
311 }
312 def LLVM_StoreOp :
313     MemoryOpWithAlignmentAndAttributes,
314     LLVM_ZeroResultOp<"store"> {
315   let arguments = (ins LLVM_LoadableType:$value,
316                    LLVM_PointerTo<LLVM_LoadableType>:$addr,
317                    OptionalAttr<I64Attr>:$alignment, UnitAttr:$volatile_,
318                    UnitAttr:$nontemporal);
319   string llvmBuilder = [{
320     auto *inst = builder.CreateStore($value, $addr, $volatile_);
321   }] # setAlignmentCode # setNonTemporalMetadataCode;
322   let builders = [
323     OpBuilderDAG<(ins "Value":$value, "Value":$addr,
324       CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
325       CArg<"bool", "false">:$isNonTemporal)>
326     ];
327   let parser = [{ return parseStoreOp(parser, result); }];
328   let printer = [{ printStoreOp(p, *this); }];
329 }
330
331 // Casts.
332 class LLVM_CastOp<string mnemonic, string builderFunc, Type type,
333                   list<OpTrait> traits = []> :
334     LLVM_OneResultOp<mnemonic,
335            !listconcat([NoSideEffect], traits)>,
336     LLVM_Builder<"$res = builder." # builderFunc # "($arg, $_resultType);"> {
337   let arguments = (ins type:$arg);
338   let parser = [{ return mlir::impl::parseCastOp(parser, result); }];
339   let printer = [{ mlir::impl::printCastOp(this->getOperation(), p); }];
340 }
341 def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "CreateBitCast",
342                                  LLVM_AnyNonAggregate>;
343 def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "CreateAddrSpaceCast",
344                                        LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>;
345 def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "CreateIntToPtr",
346                                   LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
347 def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "CreatePtrToInt",
348                                   LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>;
349 def LLVM_SExtOp : LLVM_CastOp<"sext", "CreateSExt",
350                               LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
351 def LLVM_ZExtOp : LLVM_CastOp<"zext", "CreateZExt",
352                               LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
353 def LLVM_TruncOp : LLVM_CastOp<"trunc", "CreateTrunc",
354                                LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
355 def LLVM_SIToFPOp : LLVM_CastOp<"sitofp", "CreateSIToFP",
356                                 LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
357 def LLVM_UIToFPOp : LLVM_CastOp<"uitofp", "CreateUIToFP",
358                                 LLVM_ScalarOrVectorOf<LLVM_AnyInteger>>;
359 def LLVM_FPToSIOp : LLVM_CastOp<"fptosi", "CreateFPToSI",
360                                 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>;
361 def LLVM_FPToUIOp : LLVM_CastOp<"fptoui", "CreateFPToUI",
362                                 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>;
363 def LLVM_FPExtOp : LLVM_CastOp<"fpext", "CreateFPExt",
364                                 LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>;
365 def LLVM_FPTruncOp : LLVM_CastOp<"fptrunc", "CreateFPTrunc",
366                                  LLVM_ScalarOrVectorOf<LLVM_AnyFloat>>;
367
368 // Call-related operations.
369 def LLVM_InvokeOp : LLVM_Op<"invoke", [
370                       AttrSizedOperandSegments,
371                       DeclareOpInterfaceMethods<BranchOpInterface>,
372                       Terminator
373                     ]>,
374                     Results<(outs Variadic<LLVM_Type>)> {
375   let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
376                    Variadic<LLVM_Type>:$operands,
377                    Variadic<LLVM_Type>:$normalDestOperands,
378                    Variadic<LLVM_Type>:$unwindDestOperands);
379   let successors = (successor AnySuccessor:$normalDest,
380                               AnySuccessor:$unwindDest);
381
382   let builders = [
383     OpBuilderDAG<(ins "TypeRange":$tys, "FlatSymbolRefAttr":$callee,
384       "ValueRange":$ops, "Block*":$normal, "ValueRange":$normalOps,
385       "Block*":$unwind, "ValueRange":$unwindOps),
386     [{
387       $_state.addAttribute("callee", callee);
388       build($_builder, $_state, tys, ops, normal, normalOps, unwind, unwindOps);
389     }]>,
390     OpBuilderDAG<(ins "TypeRange":$tys, "ValueRange":$ops, "Block*":$normal,
391       "ValueRange":$normalOps, "Block*":$unwind, "ValueRange":$unwindOps),
392     [{
393       build($_builder, $_state, tys, /*callee=*/FlatSymbolRefAttr(), ops, normalOps,
394             unwindOps, normal, unwind);
395     }]>];
396   let verifier = [{ return ::verify(*this);  }];
397   let parser = [{ return parseInvokeOp(parser, result); }];
398   let printer = [{ printInvokeOp(p, *this); }];
399 }
400
401 def LLVM_LandingpadOp : LLVM_OneResultOp<"landingpad"> {
402   let arguments = (ins UnitAttr:$cleanup, Variadic<LLVM_Type>);
403   let verifier = [{ return ::verify(*this); }];
404   let parser = [{ return parseLandingpadOp(parser, result); }];
405   let printer = [{ printLandingpadOp(p, *this); }];
406 }
407
408 def LLVM_CallOp : LLVM_Op<"call">,
409                   Results<(outs Variadic<LLVM_Type>)> {
410   let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
411                    Variadic<LLVM_Type>);
412   let builders = [
413     OpBuilderDAG<(ins "LLVMFuncOp":$func, "ValueRange":$operands,
414       CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes),
415     [{
416       LLVMType resultType = func.getType().getFunctionResultType();
417       if (!resultType.isVoidTy())
418         $_state.addTypes(resultType);
419       $_state.addAttribute("callee", $_builder.getSymbolRefAttr(func));
420       $_state.addAttributes(attributes);
421       $_state.addOperands(operands);
422     }]>];
423   let verifier = [{ return ::verify(*this); }];
424   let parser = [{ return parseCallOp(parser, result); }];
425   let printer = [{ printCallOp(p, *this); }];
426 }
427 def LLVM_ExtractElementOp : LLVM_OneResultOp<"extractelement", [NoSideEffect]> {
428   let arguments = (ins LLVM_AnyVector:$vector, LLVM_AnyInteger:$position);
429   string llvmBuilder = [{
430     $res = builder.CreateExtractElement($vector, $position);
431   }];
432   let builders = [
433     OpBuilderDAG<(ins "Value":$vector, "Value":$position,
434       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>];
435   let parser = [{ return parseExtractElementOp(parser, result); }];
436   let printer = [{ printExtractElementOp(p, *this); }];
437 }
438 def LLVM_ExtractValueOp : LLVM_OneResultOp<"extractvalue", [NoSideEffect]> {
439   let arguments = (ins LLVM_AnyAggregate:$container, ArrayAttr:$position);
440   string llvmBuilder = [{
441     $res = builder.CreateExtractValue($container, extractPosition($position));
442   }];
443   let parser = [{ return parseExtractValueOp(parser, result); }];
444   let printer = [{ printExtractValueOp(p, *this); }];
445 }
446 def LLVM_InsertElementOp : LLVM_OneResultOp<"insertelement", [NoSideEffect]> {
447   let arguments = (ins LLVM_AnyVector:$vector, LLVM_PrimitiveType:$value,
448                    LLVM_AnyInteger:$position);
449   string llvmBuilder = [{
450     $res = builder.CreateInsertElement($vector, $value, $position);
451   }];
452   let parser = [{ return parseInsertElementOp(parser, result); }];
453   let printer = [{ printInsertElementOp(p, *this); }];
454 }
455 def LLVM_InsertValueOp : LLVM_OneResultOp<"insertvalue", [NoSideEffect]> {
456   let arguments = (ins LLVM_AnyAggregate:$container, LLVM_PrimitiveType:$value,
457                    ArrayAttr:$position);
458   string llvmBuilder = [{
459     $res = builder.CreateInsertValue($container, $value,
460                                      extractPosition($position));
461   }];
462   let builders = [
463     OpBuilderDAG<(ins "Value":$container, "Value":$value, "ArrayAttr":$position),
464     [{
465       build($_builder, $_state, container.getType(), container, value, position);
466     }]>];
467   let parser = [{ return parseInsertValueOp(parser, result); }];
468   let printer = [{ printInsertValueOp(p, *this); }];
469 }
470 def LLVM_ShuffleVectorOp : LLVM_OneResultOp<"shufflevector", [NoSideEffect]> {
471   let arguments = (ins LLVM_AnyVector:$v1, LLVM_AnyVector:$v2, ArrayAttr:$mask);
472   string llvmBuilder = [{
473       SmallVector<unsigned, 4> position = extractPosition($mask);
474       SmallVector<int, 4> mask(position.begin(), position.end());
475       $res = builder.CreateShuffleVector($v1, $v2, mask);
476   }];
477   let builders = [
478     OpBuilderDAG<(ins "Value":$v1, "Value":$v2, "ArrayAttr":$mask,
479       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>];
480   let verifier = [{
481     auto wrappedVectorType1 = v1().getType().cast<LLVMType>();
482     auto wrappedVectorType2 = v2().getType().cast<LLVMType>();
483     if (!wrappedVectorType2.isVectorTy())
484       return emitOpError("expected LLVM IR Dialect vector type for operand #2");
485     if (wrappedVectorType1.getVectorElementType() !=
486         wrappedVectorType2.getVectorElementType())
487       return emitOpError("expected matching LLVM IR Dialect element types");
488     return success();
489   }];
490   let parser = [{ return parseShuffleVectorOp(parser, result); }];
491   let printer = [{ printShuffleVectorOp(p, *this); }];
492 }
493
494 // Misc operations.
495 def LLVM_SelectOp
496     : LLVM_OneResultOp<"select",
497           [NoSideEffect, AllTypesMatch<["trueValue", "falseValue", "res"]>]>,
498       LLVM_Builder<
499           "$res = builder.CreateSelect($condition, $trueValue, $falseValue);"> {
500   let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_i1>:$condition,
501                    LLVM_Type:$trueValue, LLVM_Type:$falseValue);
502   let builders = [
503     OpBuilderDAG<(ins "Value":$condition, "Value":$lhs, "Value":$rhs),
504     [{
505       build($_builder, $_state, lhs.getType(), condition, lhs, rhs);
506     }]>];
507   let assemblyFormat = "operands attr-dict `:` type($condition) `,` type($res)";
508 }
509 def LLVM_FreezeOp : LLVM_OneResultOp<"freeze", [SameOperandsAndResultType]> {
510   let arguments = (ins LLVM_Type:$val);
511   let assemblyFormat = "$val attr-dict `:` type($val)";
512   string llvmBuilder = "builder.CreateFreeze($val);";
513 }
514
515 // Terminators.
516 def LLVM_BrOp : LLVM_TerminatorOp<"br",
517     [DeclareOpInterfaceMethods<BranchOpInterface>, NoSideEffect]> {
518   let arguments = (ins Variadic<LLVM_Type>:$destOperands);
519   let successors = (successor AnySuccessor:$dest);
520   let assemblyFormat = [{
521     $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict
522   }];
523   let builders = [LLVM_TerminatorPassthroughOpBuilder];
524 }
525 def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br",
526     [AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>,
527      NoSideEffect]> {
528   let arguments = (ins LLVM_i1:$condition,
529                    Variadic<LLVM_Type>:$trueDestOperands,
530                    Variadic<LLVM_Type>:$falseDestOperands,
531                    OptionalAttr<ElementsAttr>:$branch_weights);
532   let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
533   let assemblyFormat = [{
534     $condition ( `weights` `(` $branch_weights^ `)` )? `,`
535     $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,`
536     $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)?
537     attr-dict
538   }];
539
540   let builders = [
541     OpBuilderDAG<(ins "Value":$condition, "Block *":$trueDest,
542       "ValueRange":$trueOperands, "Block *":$falseDest,
543       "ValueRange":$falseOperands,
544       CArg<"Optional<std::pair<uint32_t, uint32_t>>", "{}">:$weights),
545     [{
546         ElementsAttr weightsAttr;
547         if (weights) {
548           weightsAttr =
549               $_builder.getI32VectorAttr({static_cast<int32_t>(weights->first),
550                                        static_cast<int32_t>(weights->second)});
551         }
552         build($_builder, $_state, condition, trueOperands, falseOperands, weightsAttr,
553               trueDest, falseDest);
554   }]>,
555   OpBuilderDAG<(ins "Value":$condition, "Block *":$trueDest,
556     "Block *":$falseDest, CArg<"ValueRange", "{}">:$falseOperands),
557   [{
558       build($_builder, $_state, condition, trueDest, ValueRange(), falseDest,
559             falseOperands);
560   }]>, LLVM_TerminatorPassthroughOpBuilder];
561 }
562 def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]> {
563   let arguments = (ins Variadic<LLVM_Type>:$args);
564   string llvmBuilder = [{
565     if ($_numOperands != 0)
566       builder.CreateRet($args[0]);
567     else
568       builder.CreateRetVoid();
569   }];
570
571   let verifier = [{
572     if (getNumOperands() > 1)
573       return emitOpError("expects at most 1 operand");
574     return success();
575   }];
576
577   let parser = [{ return parseReturnOp(parser, result); }];
578   let printer = [{ printReturnOp(p, *this); }];
579 }
580 def LLVM_ResumeOp : LLVM_TerminatorOp<"resume", []> {
581   let arguments = (ins LLVM_Type:$value);
582   string llvmBuilder = [{ builder.CreateResume($value); }];
583   let verifier = [{
584     if (!isa_and_nonnull<LandingpadOp>(value().getDefiningOp()))
585       return emitOpError("expects landingpad value as operand");
586     // No check for personality of function - landingpad op verifies it.
587     return success();
588   }];
589
590   let assemblyFormat = "$value attr-dict `:` type($value)";
591 }
592 def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable", []> {
593   string llvmBuilder = [{ builder.CreateUnreachable(); }];
594   let parser = [{ return success(); }];
595   let printer = [{ p << getOperationName(); }];
596 }
597
598 ////////////////////////////////////////////////////////////////////////////////
599 // Auxiliary operations (do not appear in LLVM IR but necessary for the dialect
600 // to work correctly).
601 ////////////////////////////////////////////////////////////////////////////////
602
603 // Linkage attribute is used on functions and globals. The order follows that of
604 // https://llvm.org/docs/LangRef.html#linkage-types. The names are equivalent to
605 // visible names in the IR rather than to enum values names in llvm::GlobalValue
606 // since the latter is easier to change.
607 def LinkagePrivate
608     : LLVM_EnumAttrCase<"Private", "private", "PrivateLinkage", 0>;
609 def LinkageInternal
610     : LLVM_EnumAttrCase<"Internal", "internal", "InternalLinkage", 1>;
611 def LinkageAvailableExternally
612     : LLVM_EnumAttrCase<"AvailableExternally", "available_externally",
613                         "AvailableExternallyLinkage", 2>;
614 def LinkageLinkonce
615     : LLVM_EnumAttrCase<"Linkonce", "linkonce", "LinkOnceAnyLinkage", 3>;
616 def LinkageWeak
617     : LLVM_EnumAttrCase<"Weak", "weak", "WeakAnyLinkage", 4>;
618 def LinkageCommon
619     : LLVM_EnumAttrCase<"Common", "common", "CommonLinkage", 5>;
620 def LinkageAppending
621     : LLVM_EnumAttrCase<"Appending", "appending", "AppendingLinkage", 6>;
622 def LinkageExternWeak
623    : LLVM_EnumAttrCase<"ExternWeak", "extern_weak", "ExternalWeakLinkage", 7>;
624 def LinkageLinkonceODR
625     : LLVM_EnumAttrCase<"LinkonceODR", "linkonce_odr", "LinkOnceODRLinkage", 8>;
626 def LinkageWeakODR
627     : LLVM_EnumAttrCase<"WeakODR", "weak_odr", "WeakODRLinkage", 9>;
628 def LinkageExternal
629     : LLVM_EnumAttrCase<"External", "external", "ExternalLinkage", 10>;
630
631 def Linkage : LLVM_EnumAttr<
632     "Linkage",
633     "::llvm::GlobalValue::LinkageTypes",
634     "LLVM linkage types",
635     [LinkagePrivate, LinkageInternal, LinkageAvailableExternally,
636      LinkageLinkonce, LinkageWeak, LinkageCommon, LinkageAppending,
637      LinkageExternWeak, LinkageLinkonceODR, LinkageWeakODR, LinkageExternal]> {
638   let cppNamespace = "::mlir::LLVM";
639 }
640
641
642 def LLVM_AddressOfOp : LLVM_OneResultOp<"mlir.addressof"> {
643   let arguments = (ins FlatSymbolRefAttr:$global_name);
644
645   let summary = "Creates a pointer pointing to a global or a function";
646
647   let builders = [
648     OpBuilderDAG<(ins "LLVMType":$resType, "StringRef":$name,
649       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
650     [{
651       $_state.addAttribute("global_name",$_builder.getSymbolRefAttr(name));
652       $_state.addAttributes(attrs);
653       $_state.addTypes(resType);}]>,
654     OpBuilderDAG<(ins "GlobalOp":$global,
655       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
656     [{
657       build($_builder, $_state,
658             global.getType().getPointerTo(global.addr_space()),
659             global.sym_name(), attrs);}]>,
660     OpBuilderDAG<(ins "LLVMFuncOp":$func,
661       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
662     [{
663       build($_builder, $_state,
664             func.getType().getPointerTo(), func.getName(), attrs);}]>
665   ];
666
667   let extraClassDeclaration = [{
668     /// Return the llvm.mlir.global operation that defined the value referenced
669     /// here.
670     GlobalOp getGlobal();
671
672     /// Return the llvm.func operation that is referenced here.
673     LLVMFuncOp getFunction();
674   }];
675
676   let assemblyFormat = "$global_name attr-dict `:` type($res)";
677   let verifier = "return ::verify(*this);";
678 }
679
680 def LLVM_GlobalOp
681     : LLVM_ZeroResultOp<"mlir.global",
682                         [IsolatedFromAbove,
683                          SingleBlockImplicitTerminator<"ReturnOp">, Symbol]> {
684   let arguments = (ins
685     TypeAttr:$type,
686     UnitAttr:$constant,
687     StrAttr:$sym_name,
688     Linkage:$linkage,
689     OptionalAttr<AnyAttr>:$value,
690     DefaultValuedAttr<Confined<I32Attr, [IntNonNegative]>, "0">:$addr_space
691   );
692   let summary = "LLVM dialect global.";
693   let description = [{
694     Can contain an optional initializer region or attribute for simple
695     initializers.
696
697     Examples:
698       // Initialized using an attribute.
699       llvm.mlir.global @a("abc") : !llvm<"[3 x i8]">
700       // Initialized using a region.
701       llvm.mlir.global constant @b() : !llvm<"i32*"> {
702         %0 = llvm.constant(0 : i32) : !llvm.i32
703         %1 = llvm.inttoptr %0 : !llvm.i32 to !llvm<"i32*">
704         llvm.return %1 : !llvm<"i32*">
705       }
706   }];
707   let regions = (region AnyRegion:$initializer);
708
709   let builders = [
710     OpBuilderDAG<(ins "LLVMType":$type, "bool":$isConstant, "Linkage":$linkage,
711       "StringRef":$name, "Attribute":$value, CArg<"unsigned", "0">:$addrSpace,
712       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
713   ];
714
715   let extraClassDeclaration = [{
716     /// Return the LLVM type of the global.
717     LLVMType getType() {
718       return type().cast<LLVMType>();
719     }
720     /// Return the initializer attribute if it exists, or a null attribute.
721     Attribute getValueOrNull() {
722       return value().getValueOr(Attribute());
723     }
724     /// Return the initializer region. This may be empty, but if it is not it
725     /// terminates in an `llvm.return` op with the initializer value.
726     Region &getInitializerRegion() {
727       return getOperation()->getRegion(0);
728     }
729     /// Return the initializer block. If the initializer region is empty this
730     /// is nullptr. If it is not nullptr, it terminates with an `llvm.return`
731     /// op with the initializer value.
732     Block *getInitializerBlock() {
733       return getInitializerRegion().empty() ?
734         nullptr : &getInitializerRegion().front();
735     }
736   }];
737
738   let printer = "printGlobalOp(p, *this);";
739   let parser = "return parseGlobalOp(parser, result);";
740   let verifier = "return ::verify(*this);";
741 }
742
743 def LLVM_LLVMFuncOp
744     : LLVM_ZeroResultOp<"func", [AutomaticAllocationScope, IsolatedFromAbove,
745                                  FunctionLike, Symbol]> {
746   let summary = "LLVM dialect function, has wrapped LLVM IR function type";
747
748   let arguments = (ins DefaultValuedAttr<Linkage, "Linkage::External">:$linkage,
749                    OptionalAttr<FlatSymbolRefAttr>:$personality,
750                    OptionalAttr<ArrayAttr>:$passthrough);
751
752   let regions = (region AnyRegion:$body);
753
754   let skipDefaultBuilders = 1;
755
756   let builders = [
757     OpBuilderDAG<(ins "StringRef":$name, "LLVMType":$type,
758       CArg<"Linkage", "Linkage::External">:$linkage,
759       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
760       CArg<"ArrayRef<MutableDictionaryAttr>", "{}">:$argAttrs)>
761   ];
762
763   let extraClassDeclaration = [{
764     // Add an entry block to an empty function, and set up the block arguments
765     // to match the signature of the function.
766     Block *addEntryBlock();
767
768     LLVMType getType() {
769       return getAttrOfType<TypeAttr>(getTypeAttrName())
770           .getValue().cast<LLVMType>();
771     }
772     bool isVarArg() {
773       return getType().isFunctionVarArg();
774     }
775
776     // Hook for OpTrait::FunctionLike, returns the number of function arguments`.
777     // Depends on the type attribute being correct as checked by verifyType.
778     unsigned getNumFuncArguments();
779
780     // Hook for OpTrait::FunctionLike, returns the number of function results.
781     // Depends on the type attribute being correct as checked by verifyType.
782     unsigned getNumFuncResults();
783
784     // Hook for OpTrait::FunctionLike, called after verifying that the 'type'
785     // attribute is present.  This can check for preconditions of the
786     // getNumArguments hook not failing.
787     LogicalResult verifyType();
788   }];
789
790   let verifier = [{ return ::verify(*this); }];
791   let printer = [{ printLLVMFuncOp(p, *this); }];
792   let parser = [{ return parseLLVMFuncOp(parser, result); }];
793 }
794
795 def LLVM_NullOp
796     : LLVM_OneResultOp<"mlir.null", [NoSideEffect]>,
797       LLVM_Builder<"$res = llvm::ConstantPointerNull::get("
798                    "    cast<llvm::PointerType>($_resultType));"> {
799   let assemblyFormat = "attr-dict `:` type($res)";
800   let verifier = [{ return ::verify(*this); }];
801 }
802
803 def LLVM_UndefOp : LLVM_OneResultOp<"mlir.undef", [NoSideEffect]>,
804                    LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> {
805   let assemblyFormat = "attr-dict `:` type($res)";
806 }
807 def LLVM_ConstantOp
808     : LLVM_OneResultOp<"mlir.constant", [NoSideEffect]>,
809       LLVM_Builder<"$res = getLLVMConstant($_resultType, $value, $_location);">
810 {
811   let arguments = (ins AnyAttr:$value);
812   let assemblyFormat = "`(` $value `)` attr-dict `:` type($res)";
813   let verifier = [{ return ::verify(*this); }];
814 }
815
816 def LLVM_DialectCastOp : LLVM_Op<"mlir.cast", [NoSideEffect]>,
817                          Results<(outs AnyType:$res)> {
818   let summary = "Type cast between LLVM dialect and Standard.";
819   let description = [{
820     llvm.mlir.cast op casts between Standard and LLVM dialects. It only changes
821     the dialect, but does not change compile-time or runtime semantics.
822
823     Notice that index type is not supported, as it's Standard-specific.
824
825     Example:
826       llvm.mlir.cast %v : f16 to llvm.half
827       llvm.mlir.cast %v : llvm.float to f32
828       llvm.mlir.cast %v : !llvm<"<2 x float>"> to vector<2xf32>
829   }];
830   let arguments = (ins AnyType:$in);
831   let assemblyFormat = "$in attr-dict `:` type($in) `to` type($res)";
832   let verifier = "return ::verify(*this);";
833 }
834
835 // Operations that correspond to LLVM intrinsics. With MLIR operation set being
836 // extendable, there is no reason to introduce a hard boundary between "core"
837 // operations and intrinsics. However, we systematically prefix them with
838 // "intr." to avoid potential name clashes.
839
840 class LLVM_UnaryIntrinsicOp<string func, list<OpTrait> traits = []> :
841     LLVM_OneResultIntrOp<func, [], [0],
842            !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> {
843   let arguments = (ins LLVM_Type:$in);
844 }
845
846 class LLVM_BinarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> :
847     LLVM_OneResultIntrOp<func, [], [0],
848            !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> {
849   let arguments = (ins LLVM_Type:$a, LLVM_Type:$b);
850 }
851
852 class LLVM_TernarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> :
853     LLVM_OneResultIntrOp<func, [], [0],
854            !listconcat([NoSideEffect, SameOperandsAndResultType], traits)> {
855   let arguments = (ins LLVM_Type:$a, LLVM_Type:$b, LLVM_Type:$c);
856 }
857
858 def LLVM_CopySignOp : LLVM_BinarySameArgsIntrinsicOp<"copysign">;
859 def LLVM_CosOp : LLVM_UnaryIntrinsicOp<"cos">;
860 def LLVM_ExpOp : LLVM_UnaryIntrinsicOp<"exp">;
861 def LLVM_Exp2Op : LLVM_UnaryIntrinsicOp<"exp2">;
862 def LLVM_FAbsOp : LLVM_UnaryIntrinsicOp<"fabs">;
863 def LLVM_FCeilOp : LLVM_UnaryIntrinsicOp<"ceil">;
864 def LLVM_FFloorOp : LLVM_UnaryIntrinsicOp<"floor">;
865 def LLVM_FMAOp : LLVM_TernarySameArgsIntrinsicOp<"fma">;
866 def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrinsicOp<"fmuladd">;
867 def LLVM_Log10Op : LLVM_UnaryIntrinsicOp<"log10">;
868 def LLVM_Log2Op : LLVM_UnaryIntrinsicOp<"log2">;
869 def LLVM_LogOp : LLVM_UnaryIntrinsicOp<"log">;
870 def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0]> {
871   let arguments = (ins LLVM_Type:$addr, LLVM_Type:$rw, LLVM_Type:$hint,
872                    LLVM_Type:$cache);
873 }
874 def LLVM_SinOp : LLVM_UnaryIntrinsicOp<"sin">;
875 def LLVM_SqrtOp : LLVM_UnaryIntrinsicOp<"sqrt">;
876 def LLVM_PowOp : LLVM_BinarySameArgsIntrinsicOp<"pow">;
877 def LLVM_BitReverseOp : LLVM_UnaryIntrinsicOp<"bitreverse">;
878 def LLVM_CtPopOp : LLVM_UnaryIntrinsicOp<"ctpop">;
879 def LLVM_MaxNumOp : LLVM_BinarySameArgsIntrinsicOp<"maxnum">;
880 def LLVM_MinNumOp : LLVM_BinarySameArgsIntrinsicOp<"minnum">;
881 def LLVM_SMaxOp : LLVM_BinarySameArgsIntrinsicOp<"smax">;
882 def LLVM_SMinOp : LLVM_BinarySameArgsIntrinsicOp<"smin">;
883
884 def LLVM_MemcpyOp : LLVM_ZeroResultIntrOp<"memcpy", [0, 1, 2]> {
885   let arguments = (ins LLVM_Type:$dst, LLVM_Type:$src, LLVM_Type:$len,
886                    LLVM_Type:$isVolatile);
887 }
888 def LLVM_MemcpyInlineOp : LLVM_ZeroResultIntrOp<"memcpy.inline", [0, 1, 2]> {
889   let arguments = (ins LLVM_Type:$dst, LLVM_Type:$src, LLVM_Type:$len,
890                    LLVM_Type:$isVolatile);
891 }
892
893 //
894 // Vector Reductions.
895 //
896
897 def LLVM_vector_reduce_add : LLVM_VectorReduction<"add">;
898 def LLVM_vector_reduce_and : LLVM_VectorReduction<"and">;
899 def LLVM_vector_reduce_mul : LLVM_VectorReduction<"mul">;
900 def LLVM_vector_reduce_fmax : LLVM_VectorReduction<"fmax">;
901 def LLVM_vector_reduce_fmin : LLVM_VectorReduction<"fmin">;
902 def LLVM_vector_reduce_or : LLVM_VectorReduction<"or">;
903 def LLVM_vector_reduce_smax : LLVM_VectorReduction<"smax">;
904 def LLVM_vector_reduce_smin : LLVM_VectorReduction<"smin">;
905 def LLVM_vector_reduce_umax : LLVM_VectorReduction<"umax">;
906 def LLVM_vector_reduce_umin : LLVM_VectorReduction<"umin">;
907 def LLVM_vector_reduce_xor : LLVM_VectorReduction<"xor">;
908
909 def LLVM_vector_reduce_fadd : LLVM_VectorReductionAcc<"fadd">;
910 def LLVM_vector_reduce_fmul : LLVM_VectorReductionAcc<"fmul">;
911
912 //
913 // LLVM Matrix operations.
914 //
915
916 /// Create a column major, strided 2-D matrix load, as specified in the LLVM
917 /// MatrixBuilder.
918 /// data       - Start address of the matrix read
919 /// rows       - Number of rows in matrix (must be a constant)
920 /// isVolatile - True if the load operation is marked as volatile.
921 /// columns    - Number of columns in matrix (must be a constant)
922 /// stride     - Space between columns
923 def LLVM_MatrixColumnMajorLoadOp
924     : LLVM_OneResultOp<"intr.matrix.column.major.load"> {
925   let arguments = (ins LLVM_Type:$data, LLVM_Type:$stride, I1Attr:$isVolatile,
926                    I32Attr:$rows, I32Attr:$columns);
927   string llvmBuilder = [{
928     llvm::MatrixBuilder<decltype(builder)> mb(builder);
929     const llvm::DataLayout &dl =
930       builder.GetInsertBlock()->getModule()->getDataLayout();
931     llvm::Align align = dl.getABITypeAlign(
932       $data->getType()->getPointerElementType());
933     $res = mb.CreateColumnMajorLoad(
934       $data, align, $stride, $isVolatile, $rows,
935       $columns);
936   }];
937   let assemblyFormat = "$data `,` `<` `stride` `=` $stride `>` attr-dict"
938     "`:` type($res) `from` type($data) `stride` type($stride)";
939 }
940
941 /// Create a column major, strided 2-D matrix store, as specified in the LLVM
942 /// MatrixBuilder.
943 /// matrix     - Matrix to store
944 /// ptr        - Pointer to write back to
945 /// isVolatile - True if the load operation is marked as volatile.
946 /// rows       - Number of rows in matrix (must be a constant)
947 /// columns    - Number of columns in matrix (must be a constant)
948 /// stride     - Space between columns
949 def LLVM_MatrixColumnMajorStoreOp
950     : LLVM_ZeroResultOp<"intr.matrix.column.major.store"> {
951   let arguments = (ins LLVM_Type:$matrix, LLVM_Type:$data, LLVM_Type:$stride,
952                    I1Attr:$isVolatile, I32Attr:$rows, I32Attr:$columns);
953   string llvmBuilder = [{
954     llvm::MatrixBuilder<decltype(builder)> mb(builder);
955     const llvm::DataLayout &dl =
956       builder.GetInsertBlock()->getModule()->getDataLayout();
957     llvm::Align align = dl.getABITypeAlign(
958       $data->getType()->getPointerElementType());
959     mb.CreateColumnMajorStore(
960       $matrix, $data, align, $stride, $isVolatile,
961       $rows, $columns);
962   }];
963   let assemblyFormat = "$matrix `,` $data `,` `<` `stride` `=` $stride `>` "
964     "attr-dict`:` type($matrix) `to` type($data) `stride` type($stride)";
965 }
966
967 /// Create a llvm.matrix.multiply call, multiplying 2-D matrices LHS and RHS, as
968 /// specified in the LLVM MatrixBuilder.
969 def LLVM_MatrixMultiplyOp
970     : LLVM_OneResultOp<"intr.matrix.multiply"> {
971   let arguments = (ins LLVM_Type:$lhs, LLVM_Type:$rhs, I32Attr:$lhs_rows,
972                    I32Attr:$lhs_columns, I32Attr:$rhs_columns);
973   string llvmBuilder = [{
974     llvm::MatrixBuilder<decltype(builder)> mb(builder);
975     $res = mb.CreateMatrixMultiply(
976       $lhs, $rhs, $lhs_rows, $lhs_columns,
977       $rhs_columns);
978   }];
979   let assemblyFormat = "$lhs `,` $rhs attr-dict "
980     "`:` `(` type($lhs) `,` type($rhs) `)` `->` type($res)";
981 }
982
983 /// Create a llvm.matrix.transpose call, transposing a `rows` x `columns` 2-D
984 /// `matrix`, as specified in the LLVM MatrixBuilder.
985 def LLVM_MatrixTransposeOp : LLVM_OneResultOp<"intr.matrix.transpose"> {
986   let arguments = (ins LLVM_Type:$matrix, I32Attr:$rows, I32Attr:$columns);
987   string llvmBuilder = [{
988     llvm::MatrixBuilder<decltype(builder)> mb(builder);
989     $res = mb.CreateMatrixTranspose(
990       $matrix, $rows, $columns);
991   }];
992   let assemblyFormat = "$matrix attr-dict `:` type($matrix) `into` type($res)";
993 }
994
995 //
996 // LLVM masked operations.
997 //
998
999 /// Create a llvm.get.active.lane.mask to set a mask up to a given position.
1000 def LLVM_GetActiveLaneMaskOp
1001     : LLVM_OneResultIntrOp<"get.active.lane.mask", [0], [0], [NoSideEffect]> {
1002   let arguments = (ins LLVM_Type:$base, LLVM_Type:$n);
1003   let assemblyFormat = "$base `,` $n attr-dict `:` "
1004     "type($base) `,` type($n) `to` type($res)";
1005 }
1006
1007 /// Create a call to Masked Load intrinsic.
1008 def LLVM_MaskedLoadOp : LLVM_OneResultOp<"intr.masked.load"> {
1009   let arguments = (ins LLVM_Type:$data, LLVM_Type:$mask,
1010                    Variadic<LLVM_Type>:$pass_thru, I32Attr:$alignment);
1011   string llvmBuilder = [{
1012     $res = $pass_thru.empty() ? builder.CreateMaskedLoad(
1013       $data, llvm::Align($alignment), $mask) :
1014       builder.CreateMaskedLoad(
1015         $data, llvm::Align($alignment), $mask, $pass_thru[0]);
1016   }];
1017   let assemblyFormat =
1018     "operands attr-dict `:` functional-type(operands, results)";
1019 }
1020
1021 /// Create a call to Masked Store intrinsic.
1022 def LLVM_MaskedStoreOp : LLVM_ZeroResultOp<"intr.masked.store"> {
1023   let arguments = (ins LLVM_Type:$value, LLVM_Type:$data, LLVM_Type:$mask,
1024                    I32Attr:$alignment);
1025   string llvmBuilder = [{
1026     builder.CreateMaskedStore(
1027       $value, $data, llvm::Align($alignment), $mask);
1028   }];
1029   let assemblyFormat = "$value `,` $data `,` $mask attr-dict `:` "
1030     "type($value) `,` type($mask) `into` type($data)";
1031 }
1032
1033 /// Create a call to Masked Gather intrinsic.
1034 def LLVM_masked_gather : LLVM_OneResultOp<"intr.masked.gather"> {
1035   let arguments = (ins LLVM_Type:$ptrs, LLVM_Type:$mask,
1036                    Variadic<LLVM_Type>:$pass_thru, I32Attr:$alignment);
1037   string llvmBuilder = [{
1038     $res = $pass_thru.empty() ? builder.CreateMaskedGather(
1039       $ptrs, llvm::Align($alignment), $mask) :
1040       builder.CreateMaskedGather(
1041         $ptrs, llvm::Align($alignment), $mask, $pass_thru[0]);
1042   }];
1043   let assemblyFormat =
1044     "operands attr-dict `:` functional-type(operands, results)";
1045 }
1046
1047 /// Create a call to Masked Scatter intrinsic.
1048 def LLVM_masked_scatter : LLVM_ZeroResultOp<"intr.masked.scatter"> {
1049   let arguments = (ins LLVM_Type:$value, LLVM_Type:$ptrs, LLVM_Type:$mask,
1050                    I32Attr:$alignment);
1051   string llvmBuilder = [{
1052     builder.CreateMaskedScatter(
1053       $value, $ptrs, llvm::Align($alignment), $mask);
1054   }];
1055   let assemblyFormat = "$value `,` $ptrs `,` $mask attr-dict `:` "
1056     "type($value) `,` type($mask) `into` type($ptrs)";
1057 }
1058
1059 /// Create a call to Masked Expand Load intrinsic.
1060 def LLVM_masked_expandload : LLVM_IntrOp<"masked.expandload", [0], [], [], 1> {
1061   let arguments = (ins LLVM_Type, LLVM_Type, LLVM_Type);
1062 }
1063
1064 /// Create a call to Masked Compress Store intrinsic.
1065 def LLVM_masked_compressstore
1066     : LLVM_IntrOp<"masked.compressstore", [], [0], [], 0> {
1067   let arguments = (ins LLVM_Type, LLVM_Type, LLVM_Type);
1068 }
1069
1070 //
1071 // Atomic operations.
1072 //
1073
1074 def AtomicBinOpXchg : I64EnumAttrCase<"xchg", 0>;
1075 def AtomicBinOpAdd  : I64EnumAttrCase<"add", 1>;
1076 def AtomicBinOpSub  : I64EnumAttrCase<"sub", 2>;
1077 def AtomicBinOpAnd  : I64EnumAttrCase<"_and", 3>;
1078 def AtomicBinOpNand : I64EnumAttrCase<"nand", 4>;
1079 def AtomicBinOpOr   : I64EnumAttrCase<"_or", 5>;
1080 def AtomicBinOpXor  : I64EnumAttrCase<"_xor", 6>;
1081 def AtomicBinOpMax  : I64EnumAttrCase<"max", 7>;
1082 def AtomicBinOpMin  : I64EnumAttrCase<"min", 8>;
1083 def AtomicBinOpUMax : I64EnumAttrCase<"umax", 9>;
1084 def AtomicBinOpUMin : I64EnumAttrCase<"umin", 10>;
1085 def AtomicBinOpFAdd : I64EnumAttrCase<"fadd", 11>;
1086 def AtomicBinOpFSub : I64EnumAttrCase<"fsub", 12>;
1087 def AtomicBinOp : I64EnumAttr<
1088     "AtomicBinOp",
1089     "llvm.atomicrmw binary operations",
1090     [AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd,
1091      AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax,
1092      AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd,
1093      AtomicBinOpFSub]> {
1094   let cppNamespace = "::mlir::LLVM";
1095 }
1096
1097 def AtomicOrderingNotAtomic              : I64EnumAttrCase<"not_atomic", 0>;
1098 def AtomicOrderingUnordered              : I64EnumAttrCase<"unordered", 1>;
1099 def AtomicOrderingMonotonic              : I64EnumAttrCase<"monotonic", 2>;
1100 def AtomicOrderingAcquire                : I64EnumAttrCase<"acquire", 4>;
1101 def AtomicOrderingRelease                : I64EnumAttrCase<"release", 5>;
1102 def AtomicOrderingAcquireRelease         : I64EnumAttrCase<"acq_rel", 6>;
1103 def AtomicOrderingSequentiallyConsistent : I64EnumAttrCase<"seq_cst", 7>;
1104 def AtomicOrdering : I64EnumAttr<
1105     "AtomicOrdering",
1106     "Atomic ordering for LLVM's memory model",
1107     [AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic,
1108      AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcquireRelease,
1109      AtomicOrderingSequentiallyConsistent]> {
1110   let cppNamespace = "::mlir::LLVM";
1111 }
1112
1113 def LLVM_AtomicRMWType : AnyTypeOf<[LLVM_AnyFloat, LLVM_AnyInteger]>;
1114
1115 def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw">,
1116     Results<(outs LLVM_Type:$res)> {
1117   let arguments = (ins AtomicBinOp:$bin_op,
1118                    LLVM_PointerTo<LLVM_AtomicRMWType>:$ptr,
1119                    LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering);
1120   let llvmBuilder = [{
1121     $res = builder.CreateAtomicRMW(getLLVMAtomicBinOp($bin_op), $ptr, $val,
1122                                    getLLVMAtomicOrdering($ordering));
1123   }];
1124   let parser = [{ return parseAtomicRMWOp(parser, result); }];
1125   let printer = [{ printAtomicRMWOp(p, *this); }];
1126   let verifier = "return ::verify(*this);";
1127 }
1128
1129 def LLVM_AtomicCmpXchgType : AnyTypeOf<[LLVM_AnyInteger, LLVM_AnyPointer]>;
1130
1131 def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg">, Results<(outs LLVM_Type:$res)> {
1132   let arguments = (ins LLVM_PointerTo<LLVM_AtomicCmpXchgType>:$ptr,
1133                    LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val,
1134                    AtomicOrdering:$success_ordering,
1135                    AtomicOrdering:$failure_ordering);
1136   let llvmBuilder = [{
1137     $res = builder.CreateAtomicCmpXchg($ptr, $cmp, $val,
1138                    getLLVMAtomicOrdering($success_ordering),
1139                    getLLVMAtomicOrdering($failure_ordering));
1140   }];
1141   let parser = [{ return parseAtomicCmpXchgOp(parser, result); }];
1142   let printer = [{ printAtomicCmpXchgOp(p, *this); }];
1143   let verifier = "return ::verify(*this);";
1144 }
1145
1146 def LLVM_AssumeOp : LLVM_Op<"intr.assume", []> {
1147   let arguments = (ins LLVM_Type:$cond);
1148   let llvmBuilder = [{
1149     llvm::Module *module = builder.GetInsertBlock()->getModule();
1150     llvm::Function *fn =
1151         llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::assume, {});
1152     builder.CreateCall(fn, {$cond});
1153   }];
1154 }
1155
1156 def LLVM_FenceOp : LLVM_ZeroResultOp<"fence", []> {
1157   let arguments = (ins AtomicOrdering:$ordering, StrAttr:$syncscope);
1158   let llvmBuilder = [{
1159     llvm::LLVMContext &llvmContext = builder.getContext();
1160     builder.CreateFence(getLLVMAtomicOrdering($ordering),
1161       llvmContext.getOrInsertSyncScopeID($syncscope));
1162   }];
1163   let parser = [{ return parseFenceOp(parser, result); }];
1164   let printer = [{ printFenceOp(p, *this); }];
1165   let verifier = "return ::verify(*this);";
1166 }
1167 #endif // LLVMIR_OPS