1 //===- LLVMDialect.cpp - LLVM IR Ops and Dialect registration -------------===//
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 file defines the types and operation details for the LLVM IR dialect in
10 // MLIR, and the LLVM IR dialect.  It also registers the dialect.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
14 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
15 #include "mlir/IR/Builders.h"
16 #include "mlir/IR/BuiltinOps.h"
17 #include "mlir/IR/BuiltinTypes.h"
18 #include "mlir/IR/DialectImplementation.h"
19 #include "mlir/IR/FunctionImplementation.h"
20 #include "mlir/IR/MLIRContext.h"
21 
22 #include "llvm/ADT/StringSwitch.h"
23 #include "llvm/AsmParser/Parser.h"
24 #include "llvm/Bitcode/BitcodeReader.h"
25 #include "llvm/Bitcode/BitcodeWriter.h"
26 #include "llvm/IR/Attributes.h"
27 #include "llvm/IR/Function.h"
28 #include "llvm/IR/Type.h"
29 #include "llvm/Support/Mutex.h"
30 #include "llvm/Support/SourceMgr.h"
31 
32 using namespace mlir;
33 using namespace mlir::LLVM;
34 
35 static constexpr const char kVolatileAttrName[] = "volatile_";
36 static constexpr const char kNonTemporalAttrName[] = "nontemporal";
37 
38 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
39 #include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.cpp.inc"
40 
41 namespace mlir {
42 namespace LLVM {
43 namespace detail {
44 struct BitmaskEnumStorage : public AttributeStorage {
45   using KeyTy = uint64_t;
46 
47   BitmaskEnumStorage(KeyTy val) : value(val) {}
48 
49   bool operator==(const KeyTy &key) const { return value == key; }
50 
51   static BitmaskEnumStorage *construct(AttributeStorageAllocator &allocator,
52                                        const KeyTy &key) {
53     return new (allocator.allocate<BitmaskEnumStorage>())
54         BitmaskEnumStorage(key);
55   }
56 
57   KeyTy value = 0;
58 };
59 } // namespace detail
60 } // namespace LLVM
61 } // namespace mlir
62 
63 static auto processFMFAttr(ArrayRef<NamedAttribute> attrs) {
64   SmallVector<NamedAttribute, 8> filteredAttrs(
65       llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
66         if (attr.first == "fastmathFlags") {
67           auto defAttr = FMFAttr::get({}, attr.second.getContext());
68           return defAttr != attr.second;
69         }
70         return true;
71       }));
72   return filteredAttrs;
73 }
74 
75 static ParseResult parseLLVMOpAttrs(OpAsmParser &parser,
76                                     NamedAttrList &result) {
77   return parser.parseOptionalAttrDict(result);
78 }
79 
80 static void printLLVMOpAttrs(OpAsmPrinter &printer, Operation *op,
81                              DictionaryAttr attrs) {
82   printer.printOptionalAttrDict(processFMFAttr(attrs.getValue()));
83 }
84 
85 //===----------------------------------------------------------------------===//
86 // Printing/parsing for LLVM::CmpOp.
87 //===----------------------------------------------------------------------===//
88 static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) {
89   p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate())
90     << "\" " << op.getOperand(0) << ", " << op.getOperand(1);
91   p.printOptionalAttrDict(op.getAttrs(), {"predicate"});
92   p << " : " << op.lhs().getType();
93 }
94 
95 static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) {
96   p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate())
97     << "\" " << op.getOperand(0) << ", " << op.getOperand(1);
98   p.printOptionalAttrDict(processFMFAttr(op.getAttrs()), {"predicate"});
99   p << " : " << op.lhs().getType();
100 }
101 
102 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
103 //                 attribute-dict? `:` type
104 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use
105 //                 attribute-dict? `:` type
106 template <typename CmpPredicateType>
107 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) {
108   Builder &builder = parser.getBuilder();
109 
110   StringAttr predicateAttr;
111   OpAsmParser::OperandType lhs, rhs;
112   Type type;
113   llvm::SMLoc predicateLoc, trailingTypeLoc;
114   if (parser.getCurrentLocation(&predicateLoc) ||
115       parser.parseAttribute(predicateAttr, "predicate", result.attributes) ||
116       parser.parseOperand(lhs) || parser.parseComma() ||
117       parser.parseOperand(rhs) ||
118       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
119       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) ||
120       parser.resolveOperand(lhs, type, result.operands) ||
121       parser.resolveOperand(rhs, type, result.operands))
122     return failure();
123 
124   // Replace the string attribute `predicate` with an integer attribute.
125   int64_t predicateValue = 0;
126   if (std::is_same<CmpPredicateType, ICmpPredicate>()) {
127     Optional<ICmpPredicate> predicate =
128         symbolizeICmpPredicate(predicateAttr.getValue());
129     if (!predicate)
130       return parser.emitError(predicateLoc)
131              << "'" << predicateAttr.getValue()
132              << "' is an incorrect value of the 'predicate' attribute";
133     predicateValue = static_cast<int64_t>(predicate.getValue());
134   } else {
135     Optional<FCmpPredicate> predicate =
136         symbolizeFCmpPredicate(predicateAttr.getValue());
137     if (!predicate)
138       return parser.emitError(predicateLoc)
139              << "'" << predicateAttr.getValue()
140              << "' is an incorrect value of the 'predicate' attribute";
141     predicateValue = static_cast<int64_t>(predicate.getValue());
142   }
143 
144   result.attributes.set("predicate",
145                         parser.getBuilder().getI64IntegerAttr(predicateValue));
146 
147   // The result type is either i1 or a vector type <? x i1> if the inputs are
148   // vectors.
149   Type resultType = IntegerType::get(builder.getContext(), 1);
150   if (!isCompatibleType(type))
151     return parser.emitError(trailingTypeLoc,
152                             "expected LLVM dialect-compatible type");
153   if (LLVM::isCompatibleVectorType(type))
154     resultType = LLVM::getFixedVectorType(
155         resultType, LLVM::getVectorNumElements(type).getFixedValue());
156   assert(!type.isa<LLVM::LLVMScalableVectorType>() &&
157          "unhandled scalable vector");
158 
159   result.addTypes({resultType});
160   return success();
161 }
162 
163 //===----------------------------------------------------------------------===//
164 // Printing/parsing for LLVM::AllocaOp.
165 //===----------------------------------------------------------------------===//
166 
167 static void printAllocaOp(OpAsmPrinter &p, AllocaOp &op) {
168   auto elemTy = op.getType().cast<LLVM::LLVMPointerType>().getElementType();
169 
170   auto funcTy = FunctionType::get(op.getContext(), {op.arraySize().getType()},
171                                   {op.getType()});
172 
173   p << op.getOperationName() << ' ' << op.arraySize() << " x " << elemTy;
174   if (op.alignment().hasValue() && *op.alignment() != 0)
175     p.printOptionalAttrDict(op.getAttrs());
176   else
177     p.printOptionalAttrDict(op.getAttrs(), {"alignment"});
178   p << " : " << funcTy;
179 }
180 
181 // <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict?
182 //                 `:` type `,` type
183 static ParseResult parseAllocaOp(OpAsmParser &parser, OperationState &result) {
184   OpAsmParser::OperandType arraySize;
185   Type type, elemType;
186   llvm::SMLoc trailingTypeLoc;
187   if (parser.parseOperand(arraySize) || parser.parseKeyword("x") ||
188       parser.parseType(elemType) ||
189       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
190       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
191     return failure();
192 
193   Optional<NamedAttribute> alignmentAttr =
194       result.attributes.getNamed("alignment");
195   if (alignmentAttr.hasValue()) {
196     auto alignmentInt = alignmentAttr.getValue().second.dyn_cast<IntegerAttr>();
197     if (!alignmentInt)
198       return parser.emitError(parser.getNameLoc(),
199                               "expected integer alignment");
200     if (alignmentInt.getValue().isNullValue())
201       result.attributes.erase("alignment");
202   }
203 
204   // Extract the result type from the trailing function type.
205   auto funcType = type.dyn_cast<FunctionType>();
206   if (!funcType || funcType.getNumInputs() != 1 ||
207       funcType.getNumResults() != 1)
208     return parser.emitError(
209         trailingTypeLoc,
210         "expected trailing function type with one argument and one result");
211 
212   if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands))
213     return failure();
214 
215   result.addTypes({funcType.getResult(0)});
216   return success();
217 }
218 
219 //===----------------------------------------------------------------------===//
220 // LLVM::BrOp
221 //===----------------------------------------------------------------------===//
222 
223 Optional<MutableOperandRange>
224 BrOp::getMutableSuccessorOperands(unsigned index) {
225   assert(index == 0 && "invalid successor index");
226   return destOperandsMutable();
227 }
228 
229 //===----------------------------------------------------------------------===//
230 // LLVM::CondBrOp
231 //===----------------------------------------------------------------------===//
232 
233 Optional<MutableOperandRange>
234 CondBrOp::getMutableSuccessorOperands(unsigned index) {
235   assert(index < getNumSuccessors() && "invalid successor index");
236   return index == 0 ? trueDestOperandsMutable() : falseDestOperandsMutable();
237 }
238 
239 //===----------------------------------------------------------------------===//
240 // LLVM::SwitchOp
241 //===----------------------------------------------------------------------===//
242 
243 void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value,
244                      Block *defaultDestination, ValueRange defaultOperands,
245                      ArrayRef<int32_t> caseValues, BlockRange caseDestinations,
246                      ArrayRef<ValueRange> caseOperands,
247                      ArrayRef<int32_t> branchWeights) {
248   SmallVector<Value> flattenedCaseOperands;
249   SmallVector<int32_t> caseOperandOffsets;
250   int32_t offset = 0;
251   for (ValueRange operands : caseOperands) {
252     flattenedCaseOperands.append(operands.begin(), operands.end());
253     caseOperandOffsets.push_back(offset);
254     offset += operands.size();
255   }
256   ElementsAttr caseValuesAttr;
257   if (!caseValues.empty())
258     caseValuesAttr = builder.getI32VectorAttr(caseValues);
259   ElementsAttr caseOperandOffsetsAttr;
260   if (!caseOperandOffsets.empty())
261     caseOperandOffsetsAttr = builder.getI32VectorAttr(caseOperandOffsets);
262 
263   ElementsAttr weightsAttr;
264   if (!branchWeights.empty())
265     weightsAttr = builder.getI32VectorAttr(llvm::to_vector<4>(branchWeights));
266 
267   build(builder, result, value, defaultOperands, flattenedCaseOperands,
268         caseValuesAttr, caseOperandOffsetsAttr, weightsAttr, defaultDestination,
269         caseDestinations);
270 }
271 
272 /// <cases> ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)?
273 ///             ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )?
274 static ParseResult
275 parseSwitchOpCases(OpAsmParser &parser, ElementsAttr &caseValues,
276                    SmallVectorImpl<Block *> &caseDestinations,
277                    SmallVectorImpl<OpAsmParser::OperandType> &caseOperands,
278                    SmallVectorImpl<Type> &caseOperandTypes,
279                    ElementsAttr &caseOperandOffsets) {
280   SmallVector<int32_t> values;
281   SmallVector<int32_t> offsets;
282   int32_t value, offset = 0;
283   do {
284     OptionalParseResult integerParseResult = parser.parseOptionalInteger(value);
285     if (values.empty() && !integerParseResult.hasValue())
286       return success();
287 
288     if (!integerParseResult.hasValue() || integerParseResult.getValue())
289       return failure();
290     values.push_back(value);
291 
292     Block *destination;
293     SmallVector<OpAsmParser::OperandType> operands;
294     if (parser.parseColon() || parser.parseSuccessor(destination))
295       return failure();
296     if (!parser.parseOptionalLParen()) {
297       if (parser.parseRegionArgumentList(operands) ||
298           parser.parseColonTypeList(caseOperandTypes) || parser.parseRParen())
299         return failure();
300     }
301     caseDestinations.push_back(destination);
302     caseOperands.append(operands.begin(), operands.end());
303     offsets.push_back(offset);
304     offset += operands.size();
305   } while (!parser.parseOptionalComma());
306 
307   Builder &builder = parser.getBuilder();
308   caseValues = builder.getI32VectorAttr(values);
309   caseOperandOffsets = builder.getI32VectorAttr(offsets);
310 
311   return success();
312 }
313 
314 static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op,
315                                ElementsAttr caseValues,
316                                SuccessorRange caseDestinations,
317                                OperandRange caseOperands,
318                                TypeRange caseOperandTypes,
319                                ElementsAttr caseOperandOffsets) {
320   if (!caseValues)
321     return;
322 
323   size_t index = 0;
324   llvm::interleave(
325       llvm::zip(caseValues.cast<DenseIntElementsAttr>(), caseDestinations),
326       [&](auto i) {
327         p << "  ";
328         p << std::get<0>(i).getLimitedValue();
329         p << ": ";
330         p.printSuccessorAndUseList(std::get<1>(i), op.getCaseOperands(index++));
331       },
332       [&] {
333         p << ',';
334         p.printNewline();
335       });
336   p.printNewline();
337 }
338 
339 static LogicalResult verify(SwitchOp op) {
340   if ((!op.case_values() && !op.caseDestinations().empty()) ||
341       (op.case_values() &&
342        op.case_values()->size() !=
343            static_cast<int64_t>(op.caseDestinations().size())))
344     return op.emitOpError("expects number of case values to match number of "
345                           "case destinations");
346   if (op.branch_weights() &&
347       op.branch_weights()->size() != op.getNumSuccessors())
348     return op.emitError("expects number of branch weights to match number of "
349                         "successors: ")
350            << op.branch_weights()->size() << " vs " << op.getNumSuccessors();
351   return success();
352 }
353 
354 OperandRange SwitchOp::getCaseOperands(unsigned index) {
355   return getCaseOperandsMutable(index);
356 }
357 
358 MutableOperandRange SwitchOp::getCaseOperandsMutable(unsigned index) {
359   MutableOperandRange caseOperands = caseOperandsMutable();
360   if (!case_operand_offsets()) {
361     assert(caseOperands.size() == 0 &&
362            "non-empty case operands must have offsets");
363     return caseOperands;
364   }
365 
366   ElementsAttr offsets = case_operand_offsets().getValue();
367   assert(index < offsets.size() && "invalid case operand offset index");
368 
369   int64_t begin = offsets.getValue(index).cast<IntegerAttr>().getInt();
370   int64_t end = index + 1 == offsets.size()
371                     ? caseOperands.size()
372                     : offsets.getValue(index + 1).cast<IntegerAttr>().getInt();
373   return caseOperandsMutable().slice(begin, end - begin);
374 }
375 
376 Optional<MutableOperandRange>
377 SwitchOp::getMutableSuccessorOperands(unsigned index) {
378   assert(index < getNumSuccessors() && "invalid successor index");
379   return index == 0 ? defaultOperandsMutable()
380                     : getCaseOperandsMutable(index - 1);
381 }
382 
383 //===----------------------------------------------------------------------===//
384 // Builder, printer and parser for for LLVM::LoadOp.
385 //===----------------------------------------------------------------------===//
386 
387 void LoadOp::build(OpBuilder &builder, OperationState &result, Type t,
388                    Value addr, unsigned alignment, bool isVolatile,
389                    bool isNonTemporal) {
390   result.addOperands(addr);
391   result.addTypes(t);
392   if (isVolatile)
393     result.addAttribute(kVolatileAttrName, builder.getUnitAttr());
394   if (isNonTemporal)
395     result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr());
396   if (alignment != 0)
397     result.addAttribute("alignment", builder.getI64IntegerAttr(alignment));
398 }
399 
400 static void printLoadOp(OpAsmPrinter &p, LoadOp &op) {
401   p << op.getOperationName() << ' ';
402   if (op.volatile_())
403     p << "volatile ";
404   p << op.addr();
405   p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName});
406   p << " : " << op.addr().getType();
407 }
408 
409 // Extract the pointee type from the LLVM pointer type wrapped in MLIR.  Return
410 // the resulting type wrapped in MLIR, or nullptr on error.
411 static Type getLoadStoreElementType(OpAsmParser &parser, Type type,
412                                     llvm::SMLoc trailingTypeLoc) {
413   auto llvmTy = type.dyn_cast<LLVM::LLVMPointerType>();
414   if (!llvmTy)
415     return parser.emitError(trailingTypeLoc, "expected LLVM pointer type"),
416            nullptr;
417   return llvmTy.getElementType();
418 }
419 
420 // <operation> ::= `llvm.load` `volatile` ssa-use attribute-dict? `:` type
421 static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) {
422   OpAsmParser::OperandType addr;
423   Type type;
424   llvm::SMLoc trailingTypeLoc;
425 
426   if (succeeded(parser.parseOptionalKeyword("volatile")))
427     result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr());
428 
429   if (parser.parseOperand(addr) ||
430       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
431       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) ||
432       parser.resolveOperand(addr, type, result.operands))
433     return failure();
434 
435   Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
436 
437   result.addTypes(elemTy);
438   return success();
439 }
440 
441 //===----------------------------------------------------------------------===//
442 // Builder, printer and parser for LLVM::StoreOp.
443 //===----------------------------------------------------------------------===//
444 
445 void StoreOp::build(OpBuilder &builder, OperationState &result, Value value,
446                     Value addr, unsigned alignment, bool isVolatile,
447                     bool isNonTemporal) {
448   result.addOperands({value, addr});
449   result.addTypes({});
450   if (isVolatile)
451     result.addAttribute(kVolatileAttrName, builder.getUnitAttr());
452   if (isNonTemporal)
453     result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr());
454   if (alignment != 0)
455     result.addAttribute("alignment", builder.getI64IntegerAttr(alignment));
456 }
457 
458 static void printStoreOp(OpAsmPrinter &p, StoreOp &op) {
459   p << op.getOperationName() << ' ';
460   if (op.volatile_())
461     p << "volatile ";
462   p << op.value() << ", " << op.addr();
463   p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName});
464   p << " : " << op.addr().getType();
465 }
466 
467 // <operation> ::= `llvm.store` `volatile` ssa-use `,` ssa-use
468 //                 attribute-dict? `:` type
469 static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) {
470   OpAsmParser::OperandType addr, value;
471   Type type;
472   llvm::SMLoc trailingTypeLoc;
473 
474   if (succeeded(parser.parseOptionalKeyword("volatile")))
475     result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr());
476 
477   if (parser.parseOperand(value) || parser.parseComma() ||
478       parser.parseOperand(addr) ||
479       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
480       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
481     return failure();
482 
483   Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
484   if (!elemTy)
485     return failure();
486 
487   if (parser.resolveOperand(value, elemTy, result.operands) ||
488       parser.resolveOperand(addr, type, result.operands))
489     return failure();
490 
491   return success();
492 }
493 
494 ///===---------------------------------------------------------------------===//
495 /// LLVM::InvokeOp
496 ///===---------------------------------------------------------------------===//
497 
498 Optional<MutableOperandRange>
499 InvokeOp::getMutableSuccessorOperands(unsigned index) {
500   assert(index < getNumSuccessors() && "invalid successor index");
501   return index == 0 ? normalDestOperandsMutable() : unwindDestOperandsMutable();
502 }
503 
504 static LogicalResult verify(InvokeOp op) {
505   if (op.getNumResults() > 1)
506     return op.emitOpError("must have 0 or 1 result");
507 
508   Block *unwindDest = op.unwindDest();
509   if (unwindDest->empty())
510     return op.emitError(
511         "must have at least one operation in unwind destination");
512 
513   // In unwind destination, first operation must be LandingpadOp
514   if (!isa<LandingpadOp>(unwindDest->front()))
515     return op.emitError("first operation in unwind destination should be a "
516                         "llvm.landingpad operation");
517 
518   return success();
519 }
520 
521 static void printInvokeOp(OpAsmPrinter &p, InvokeOp op) {
522   auto callee = op.callee();
523   bool isDirect = callee.hasValue();
524 
525   p << op.getOperationName() << ' ';
526 
527   // Either function name or pointer
528   if (isDirect)
529     p.printSymbolName(callee.getValue());
530   else
531     p << op.getOperand(0);
532 
533   p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')';
534   p << " to ";
535   p.printSuccessorAndUseList(op.normalDest(), op.normalDestOperands());
536   p << " unwind ";
537   p.printSuccessorAndUseList(op.unwindDest(), op.unwindDestOperands());
538 
539   p.printOptionalAttrDict(op.getAttrs(),
540                           {InvokeOp::getOperandSegmentSizeAttr(), "callee"});
541   p << " : ";
542   p.printFunctionalType(
543       llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1),
544       op.getResultTypes());
545 }
546 
547 /// <operation> ::= `llvm.invoke` (function-id | ssa-use) `(` ssa-use-list `)`
548 ///                  `to` bb-id (`[` ssa-use-and-type-list `]`)?
549 ///                  `unwind` bb-id (`[` ssa-use-and-type-list `]`)?
550 ///                  attribute-dict? `:` function-type
551 static ParseResult parseInvokeOp(OpAsmParser &parser, OperationState &result) {
552   SmallVector<OpAsmParser::OperandType, 8> operands;
553   FunctionType funcType;
554   SymbolRefAttr funcAttr;
555   llvm::SMLoc trailingTypeLoc;
556   Block *normalDest, *unwindDest;
557   SmallVector<Value, 4> normalOperands, unwindOperands;
558   Builder &builder = parser.getBuilder();
559 
560   // Parse an operand list that will, in practice, contain 0 or 1 operand.  In
561   // case of an indirect call, there will be 1 operand before `(`.  In case of a
562   // direct call, there will be no operands and the parser will stop at the
563   // function identifier without complaining.
564   if (parser.parseOperandList(operands))
565     return failure();
566   bool isDirect = operands.empty();
567 
568   // Optionally parse a function identifier.
569   if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes))
570     return failure();
571 
572   if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
573       parser.parseKeyword("to") ||
574       parser.parseSuccessorAndUseList(normalDest, normalOperands) ||
575       parser.parseKeyword("unwind") ||
576       parser.parseSuccessorAndUseList(unwindDest, unwindOperands) ||
577       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
578       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(funcType))
579     return failure();
580 
581   if (isDirect) {
582     // Make sure types match.
583     if (parser.resolveOperands(operands, funcType.getInputs(),
584                                parser.getNameLoc(), result.operands))
585       return failure();
586     result.addTypes(funcType.getResults());
587   } else {
588     // Construct the LLVM IR Dialect function type that the first operand
589     // should match.
590     if (funcType.getNumResults() > 1)
591       return parser.emitError(trailingTypeLoc,
592                               "expected function with 0 or 1 result");
593 
594     Type llvmResultType;
595     if (funcType.getNumResults() == 0) {
596       llvmResultType = LLVM::LLVMVoidType::get(builder.getContext());
597     } else {
598       llvmResultType = funcType.getResult(0);
599       if (!isCompatibleType(llvmResultType))
600         return parser.emitError(trailingTypeLoc,
601                                 "expected result to have LLVM type");
602     }
603 
604     SmallVector<Type, 8> argTypes;
605     argTypes.reserve(funcType.getNumInputs());
606     for (Type ty : funcType.getInputs()) {
607       if (isCompatibleType(ty))
608         argTypes.push_back(ty);
609       else
610         return parser.emitError(trailingTypeLoc,
611                                 "expected LLVM types as inputs");
612     }
613 
614     auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes);
615     auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType);
616 
617     auto funcArguments = llvm::makeArrayRef(operands).drop_front();
618 
619     // Make sure that the first operand (indirect callee) matches the wrapped
620     // LLVM IR function type, and that the types of the other call operands
621     // match the types of the function arguments.
622     if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) ||
623         parser.resolveOperands(funcArguments, funcType.getInputs(),
624                                parser.getNameLoc(), result.operands))
625       return failure();
626 
627     result.addTypes(llvmResultType);
628   }
629   result.addSuccessors({normalDest, unwindDest});
630   result.addOperands(normalOperands);
631   result.addOperands(unwindOperands);
632 
633   result.addAttribute(
634       InvokeOp::getOperandSegmentSizeAttr(),
635       builder.getI32VectorAttr({static_cast<int32_t>(operands.size()),
636                                 static_cast<int32_t>(normalOperands.size()),
637                                 static_cast<int32_t>(unwindOperands.size())}));
638   return success();
639 }
640 
641 ///===----------------------------------------------------------------------===//
642 /// Verifying/Printing/Parsing for LLVM::LandingpadOp.
643 ///===----------------------------------------------------------------------===//
644 
645 static LogicalResult verify(LandingpadOp op) {
646   Value value;
647   if (LLVMFuncOp func = op->getParentOfType<LLVMFuncOp>()) {
648     if (!func.personality().hasValue())
649       return op.emitError(
650           "llvm.landingpad needs to be in a function with a personality");
651   }
652 
653   if (!op.cleanup() && op.getOperands().empty())
654     return op.emitError("landingpad instruction expects at least one clause or "
655                         "cleanup attribute");
656 
657   for (unsigned idx = 0, ie = op.getNumOperands(); idx < ie; idx++) {
658     value = op.getOperand(idx);
659     bool isFilter = value.getType().isa<LLVMArrayType>();
660     if (isFilter) {
661       // FIXME: Verify filter clauses when arrays are appropriately handled
662     } else {
663       // catch - global addresses only.
664       // Bitcast ops should have global addresses as their args.
665       if (auto bcOp = value.getDefiningOp<BitcastOp>()) {
666         if (auto addrOp = bcOp.arg().getDefiningOp<AddressOfOp>())
667           continue;
668         return op.emitError("constant clauses expected")
669                    .attachNote(bcOp.getLoc())
670                << "global addresses expected as operand to "
671                   "bitcast used in clauses for landingpad";
672       }
673       // NullOp and AddressOfOp allowed
674       if (value.getDefiningOp<NullOp>())
675         continue;
676       if (value.getDefiningOp<AddressOfOp>())
677         continue;
678       return op.emitError("clause #")
679              << idx << " is not a known constant - null, addressof, bitcast";
680     }
681   }
682   return success();
683 }
684 
685 static void printLandingpadOp(OpAsmPrinter &p, LandingpadOp &op) {
686   p << op.getOperationName() << (op.cleanup() ? " cleanup " : " ");
687 
688   // Clauses
689   for (auto value : op.getOperands()) {
690     // Similar to llvm - if clause is an array type then it is filter
691     // clause else catch clause
692     bool isArrayTy = value.getType().isa<LLVMArrayType>();
693     p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : "
694       << value.getType() << ") ";
695   }
696 
697   p.printOptionalAttrDict(op.getAttrs(), {"cleanup"});
698 
699   p << ": " << op.getType();
700 }
701 
702 /// <operation> ::= `llvm.landingpad` `cleanup`?
703 ///                 ((`catch` | `filter`) operand-type ssa-use)* attribute-dict?
704 static ParseResult parseLandingpadOp(OpAsmParser &parser,
705                                      OperationState &result) {
706   // Check for cleanup
707   if (succeeded(parser.parseOptionalKeyword("cleanup")))
708     result.addAttribute("cleanup", parser.getBuilder().getUnitAttr());
709 
710   // Parse clauses with types
711   while (succeeded(parser.parseOptionalLParen()) &&
712          (succeeded(parser.parseOptionalKeyword("filter")) ||
713           succeeded(parser.parseOptionalKeyword("catch")))) {
714     OpAsmParser::OperandType operand;
715     Type ty;
716     if (parser.parseOperand(operand) || parser.parseColon() ||
717         parser.parseType(ty) ||
718         parser.resolveOperand(operand, ty, result.operands) ||
719         parser.parseRParen())
720       return failure();
721   }
722 
723   Type type;
724   if (parser.parseColon() || parser.parseType(type))
725     return failure();
726 
727   result.addTypes(type);
728   return success();
729 }
730 
731 //===----------------------------------------------------------------------===//
732 // Verifying/Printing/parsing for LLVM::CallOp.
733 //===----------------------------------------------------------------------===//
734 
735 static LogicalResult verify(CallOp &op) {
736   if (op.getNumResults() > 1)
737     return op.emitOpError("must have 0 or 1 result");
738 
739   // Type for the callee, we'll get it differently depending if it is a direct
740   // or indirect call.
741   Type fnType;
742 
743   bool isIndirect = false;
744 
745   // If this is an indirect call, the callee attribute is missing.
746   Optional<StringRef> calleeName = op.callee();
747   if (!calleeName) {
748     isIndirect = true;
749     if (!op.getNumOperands())
750       return op.emitOpError(
751           "must have either a `callee` attribute or at least an operand");
752     auto ptrType = op.getOperand(0).getType().dyn_cast<LLVMPointerType>();
753     if (!ptrType)
754       return op.emitOpError("indirect call expects a pointer as callee: ")
755              << ptrType;
756     fnType = ptrType.getElementType();
757   } else {
758     Operation *callee = SymbolTable::lookupNearestSymbolFrom(op, *calleeName);
759     if (!callee)
760       return op.emitOpError()
761              << "'" << *calleeName
762              << "' does not reference a symbol in the current scope";
763     auto fn = dyn_cast<LLVMFuncOp>(callee);
764     if (!fn)
765       return op.emitOpError() << "'" << *calleeName
766                               << "' does not reference a valid LLVM function";
767 
768     fnType = fn.getType();
769   }
770 
771   LLVMFunctionType funcType = fnType.dyn_cast<LLVMFunctionType>();
772   if (!funcType)
773     return op.emitOpError("callee does not have a functional type: ") << fnType;
774 
775   // Verify that the operand and result types match the callee.
776 
777   if (!funcType.isVarArg() &&
778       funcType.getNumParams() != (op.getNumOperands() - isIndirect))
779     return op.emitOpError()
780            << "incorrect number of operands ("
781            << (op.getNumOperands() - isIndirect)
782            << ") for callee (expecting: " << funcType.getNumParams() << ")";
783 
784   if (funcType.getNumParams() > (op.getNumOperands() - isIndirect))
785     return op.emitOpError() << "incorrect number of operands ("
786                             << (op.getNumOperands() - isIndirect)
787                             << ") for varargs callee (expecting at least: "
788                             << funcType.getNumParams() << ")";
789 
790   for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i)
791     if (op.getOperand(i + isIndirect).getType() != funcType.getParamType(i))
792       return op.emitOpError() << "operand type mismatch for operand " << i
793                               << ": " << op.getOperand(i + isIndirect).getType()
794                               << " != " << funcType.getParamType(i);
795 
796   if (op.getNumResults() &&
797       op.getResult(0).getType() != funcType.getReturnType())
798     return op.emitOpError()
799            << "result type mismatch: " << op.getResult(0).getType()
800            << " != " << funcType.getReturnType();
801 
802   return success();
803 }
804 
805 static void printCallOp(OpAsmPrinter &p, CallOp &op) {
806   auto callee = op.callee();
807   bool isDirect = callee.hasValue();
808 
809   // Print the direct callee if present as a function attribute, or an indirect
810   // callee (first operand) otherwise.
811   p << op.getOperationName() << ' ';
812   if (isDirect)
813     p.printSymbolName(callee.getValue());
814   else
815     p << op.getOperand(0);
816 
817   auto args = op.getOperands().drop_front(isDirect ? 0 : 1);
818   p << '(' << args << ')';
819   p.printOptionalAttrDict(processFMFAttr(op.getAttrs()), {"callee"});
820 
821   // Reconstruct the function MLIR function type from operand and result types.
822   p << " : "
823     << FunctionType::get(op.getContext(), args.getTypes(), op.getResultTypes());
824 }
825 
826 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)`
827 //                 attribute-dict? `:` function-type
828 static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) {
829   SmallVector<OpAsmParser::OperandType, 8> operands;
830   Type type;
831   SymbolRefAttr funcAttr;
832   llvm::SMLoc trailingTypeLoc;
833 
834   // Parse an operand list that will, in practice, contain 0 or 1 operand.  In
835   // case of an indirect call, there will be 1 operand before `(`.  In case of a
836   // direct call, there will be no operands and the parser will stop at the
837   // function identifier without complaining.
838   if (parser.parseOperandList(operands))
839     return failure();
840   bool isDirect = operands.empty();
841 
842   // Optionally parse a function identifier.
843   if (isDirect)
844     if (parser.parseAttribute(funcAttr, "callee", result.attributes))
845       return failure();
846 
847   if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
848       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
849       parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
850     return failure();
851 
852   auto funcType = type.dyn_cast<FunctionType>();
853   if (!funcType)
854     return parser.emitError(trailingTypeLoc, "expected function type");
855   if (isDirect) {
856     // Make sure types match.
857     if (parser.resolveOperands(operands, funcType.getInputs(),
858                                parser.getNameLoc(), result.operands))
859       return failure();
860     result.addTypes(funcType.getResults());
861   } else {
862     // Construct the LLVM IR Dialect function type that the first operand
863     // should match.
864     if (funcType.getNumResults() > 1)
865       return parser.emitError(trailingTypeLoc,
866                               "expected function with 0 or 1 result");
867 
868     Builder &builder = parser.getBuilder();
869     Type llvmResultType;
870     if (funcType.getNumResults() == 0) {
871       llvmResultType = LLVM::LLVMVoidType::get(builder.getContext());
872     } else {
873       llvmResultType = funcType.getResult(0);
874       if (!isCompatibleType(llvmResultType))
875         return parser.emitError(trailingTypeLoc,
876                                 "expected result to have LLVM type");
877     }
878 
879     SmallVector<Type, 8> argTypes;
880     argTypes.reserve(funcType.getNumInputs());
881     for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) {
882       auto argType = funcType.getInput(i);
883       if (!isCompatibleType(argType))
884         return parser.emitError(trailingTypeLoc,
885                                 "expected LLVM types as inputs");
886       argTypes.push_back(argType);
887     }
888     auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes);
889     auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType);
890 
891     auto funcArguments =
892         ArrayRef<OpAsmParser::OperandType>(operands).drop_front();
893 
894     // Make sure that the first operand (indirect callee) matches the wrapped
895     // LLVM IR function type, and that the types of the other call operands
896     // match the types of the function arguments.
897     if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) ||
898         parser.resolveOperands(funcArguments, funcType.getInputs(),
899                                parser.getNameLoc(), result.operands))
900       return failure();
901 
902     result.addTypes(llvmResultType);
903   }
904 
905   return success();
906 }
907 
908 //===----------------------------------------------------------------------===//
909 // Printing/parsing for LLVM::ExtractElementOp.
910 //===----------------------------------------------------------------------===//
911 // Expects vector to be of wrapped LLVM vector type and position to be of
912 // wrapped LLVM i32 type.
913 void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result,
914                                    Value vector, Value position,
915                                    ArrayRef<NamedAttribute> attrs) {
916   auto vectorType = vector.getType();
917   auto llvmType = LLVM::getVectorElementType(vectorType);
918   build(b, result, llvmType, vector, position);
919   result.addAttributes(attrs);
920 }
921 
922 static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) {
923   p << op.getOperationName() << ' ' << op.vector() << "[" << op.position()
924     << " : " << op.position().getType() << "]";
925   p.printOptionalAttrDict(op.getAttrs());
926   p << " : " << op.vector().getType();
927 }
928 
929 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use
930 //                 attribute-dict? `:` type
931 static ParseResult parseExtractElementOp(OpAsmParser &parser,
932                                          OperationState &result) {
933   llvm::SMLoc loc;
934   OpAsmParser::OperandType vector, position;
935   Type type, positionType;
936   if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) ||
937       parser.parseLSquare() || parser.parseOperand(position) ||
938       parser.parseColonType(positionType) || parser.parseRSquare() ||
939       parser.parseOptionalAttrDict(result.attributes) ||
940       parser.parseColonType(type) ||
941       parser.resolveOperand(vector, type, result.operands) ||
942       parser.resolveOperand(position, positionType, result.operands))
943     return failure();
944   if (!LLVM::isCompatibleVectorType(type))
945     return parser.emitError(
946         loc, "expected LLVM dialect-compatible vector type for operand #1");
947   result.addTypes(LLVM::getVectorElementType(type));
948   return success();
949 }
950 
951 //===----------------------------------------------------------------------===//
952 // Printing/parsing for LLVM::ExtractValueOp.
953 //===----------------------------------------------------------------------===//
954 
955 static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) {
956   p << op.getOperationName() << ' ' << op.container() << op.position();
957   p.printOptionalAttrDict(op.getAttrs(), {"position"});
958   p << " : " << op.container().getType();
959 }
960 
961 // Extract the type at `position` in the wrapped LLVM IR aggregate type
962 // `containerType`.  Position is an integer array attribute where each value
963 // is a zero-based position of the element in the aggregate type.  Return the
964 // resulting type wrapped in MLIR, or nullptr on error.
965 static Type getInsertExtractValueElementType(OpAsmParser &parser,
966                                              Type containerType,
967                                              ArrayAttr positionAttr,
968                                              llvm::SMLoc attributeLoc,
969                                              llvm::SMLoc typeLoc) {
970   Type llvmType = containerType;
971   if (!isCompatibleType(containerType))
972     return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr;
973 
974   // Infer the element type from the structure type: iteratively step inside the
975   // type by taking the element type, indexed by the position attribute for
976   // structures.  Check the position index before accessing, it is supposed to
977   // be in bounds.
978   for (Attribute subAttr : positionAttr) {
979     auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>();
980     if (!positionElementAttr)
981       return parser.emitError(attributeLoc,
982                               "expected an array of integer literals"),
983              nullptr;
984     int position = positionElementAttr.getInt();
985     if (auto arrayType = llvmType.dyn_cast<LLVMArrayType>()) {
986       if (position < 0 ||
987           static_cast<unsigned>(position) >= arrayType.getNumElements())
988         return parser.emitError(attributeLoc, "position out of bounds"),
989                nullptr;
990       llvmType = arrayType.getElementType();
991     } else if (auto structType = llvmType.dyn_cast<LLVMStructType>()) {
992       if (position < 0 ||
993           static_cast<unsigned>(position) >= structType.getBody().size())
994         return parser.emitError(attributeLoc, "position out of bounds"),
995                nullptr;
996       llvmType = structType.getBody()[position];
997     } else {
998       return parser.emitError(typeLoc, "expected LLVM IR structure/array type"),
999              nullptr;
1000     }
1001   }
1002   return llvmType;
1003 }
1004 
1005 // <operation> ::= `llvm.extractvalue` ssa-use
1006 //                 `[` integer-literal (`,` integer-literal)* `]`
1007 //                 attribute-dict? `:` type
1008 static ParseResult parseExtractValueOp(OpAsmParser &parser,
1009                                        OperationState &result) {
1010   OpAsmParser::OperandType container;
1011   Type containerType;
1012   ArrayAttr positionAttr;
1013   llvm::SMLoc attributeLoc, trailingTypeLoc;
1014 
1015   if (parser.parseOperand(container) ||
1016       parser.getCurrentLocation(&attributeLoc) ||
1017       parser.parseAttribute(positionAttr, "position", result.attributes) ||
1018       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
1019       parser.getCurrentLocation(&trailingTypeLoc) ||
1020       parser.parseType(containerType) ||
1021       parser.resolveOperand(container, containerType, result.operands))
1022     return failure();
1023 
1024   auto elementType = getInsertExtractValueElementType(
1025       parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
1026   if (!elementType)
1027     return failure();
1028 
1029   result.addTypes(elementType);
1030   return success();
1031 }
1032 
1033 //===----------------------------------------------------------------------===//
1034 // Printing/parsing for LLVM::InsertElementOp.
1035 //===----------------------------------------------------------------------===//
1036 
1037 static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) {
1038   p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "["
1039     << op.position() << " : " << op.position().getType() << "]";
1040   p.printOptionalAttrDict(op.getAttrs());
1041   p << " : " << op.vector().getType();
1042 }
1043 
1044 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use
1045 //                 attribute-dict? `:` type
1046 static ParseResult parseInsertElementOp(OpAsmParser &parser,
1047                                         OperationState &result) {
1048   llvm::SMLoc loc;
1049   OpAsmParser::OperandType vector, value, position;
1050   Type vectorType, positionType;
1051   if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) ||
1052       parser.parseComma() || parser.parseOperand(vector) ||
1053       parser.parseLSquare() || parser.parseOperand(position) ||
1054       parser.parseColonType(positionType) || parser.parseRSquare() ||
1055       parser.parseOptionalAttrDict(result.attributes) ||
1056       parser.parseColonType(vectorType))
1057     return failure();
1058 
1059   if (!LLVM::isCompatibleVectorType(vectorType))
1060     return parser.emitError(
1061         loc, "expected LLVM dialect-compatible vector type for operand #1");
1062   Type valueType = LLVM::getVectorElementType(vectorType);
1063   if (!valueType)
1064     return failure();
1065 
1066   if (parser.resolveOperand(vector, vectorType, result.operands) ||
1067       parser.resolveOperand(value, valueType, result.operands) ||
1068       parser.resolveOperand(position, positionType, result.operands))
1069     return failure();
1070 
1071   result.addTypes(vectorType);
1072   return success();
1073 }
1074 
1075 //===----------------------------------------------------------------------===//
1076 // Printing/parsing for LLVM::InsertValueOp.
1077 //===----------------------------------------------------------------------===//
1078 
1079 static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) {
1080   p << op.getOperationName() << ' ' << op.value() << ", " << op.container()
1081     << op.position();
1082   p.printOptionalAttrDict(op.getAttrs(), {"position"});
1083   p << " : " << op.container().getType();
1084 }
1085 
1086 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use
1087 //                 `[` integer-literal (`,` integer-literal)* `]`
1088 //                 attribute-dict? `:` type
1089 static ParseResult parseInsertValueOp(OpAsmParser &parser,
1090                                       OperationState &result) {
1091   OpAsmParser::OperandType container, value;
1092   Type containerType;
1093   ArrayAttr positionAttr;
1094   llvm::SMLoc attributeLoc, trailingTypeLoc;
1095 
1096   if (parser.parseOperand(value) || parser.parseComma() ||
1097       parser.parseOperand(container) ||
1098       parser.getCurrentLocation(&attributeLoc) ||
1099       parser.parseAttribute(positionAttr, "position", result.attributes) ||
1100       parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
1101       parser.getCurrentLocation(&trailingTypeLoc) ||
1102       parser.parseType(containerType))
1103     return failure();
1104 
1105   auto valueType = getInsertExtractValueElementType(
1106       parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
1107   if (!valueType)
1108     return failure();
1109 
1110   if (parser.resolveOperand(container, containerType, result.operands) ||
1111       parser.resolveOperand(value, valueType, result.operands))
1112     return failure();
1113 
1114   result.addTypes(containerType);
1115   return success();
1116 }
1117 
1118 //===----------------------------------------------------------------------===//
1119 // Printing/parsing for LLVM::ReturnOp.
1120 //===----------------------------------------------------------------------===//
1121 
1122 static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) {
1123   p << op.getOperationName();
1124   p.printOptionalAttrDict(op.getAttrs());
1125   assert(op.getNumOperands() <= 1);
1126 
1127   if (op.getNumOperands() == 0)
1128     return;
1129 
1130   p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType();
1131 }
1132 
1133 // <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:`
1134 //                 type-list-no-parens
1135 static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) {
1136   SmallVector<OpAsmParser::OperandType, 1> operands;
1137   Type type;
1138 
1139   if (parser.parseOperandList(operands) ||
1140       parser.parseOptionalAttrDict(result.attributes))
1141     return failure();
1142   if (operands.empty())
1143     return success();
1144 
1145   if (parser.parseColonType(type) ||
1146       parser.resolveOperand(operands[0], type, result.operands))
1147     return failure();
1148   return success();
1149 }
1150 
1151 //===----------------------------------------------------------------------===//
1152 // Verifier for LLVM::AddressOfOp.
1153 //===----------------------------------------------------------------------===//
1154 
1155 template <typename OpTy>
1156 static OpTy lookupSymbolInModule(Operation *parent, StringRef name) {
1157   Operation *module = parent;
1158   while (module && !satisfiesLLVMModule(module))
1159     module = module->getParentOp();
1160   assert(module && "unexpected operation outside of a module");
1161   return dyn_cast_or_null<OpTy>(
1162       mlir::SymbolTable::lookupSymbolIn(module, name));
1163 }
1164 
1165 GlobalOp AddressOfOp::getGlobal() {
1166   return lookupSymbolInModule<LLVM::GlobalOp>((*this)->getParentOp(),
1167                                               global_name());
1168 }
1169 
1170 LLVMFuncOp AddressOfOp::getFunction() {
1171   return lookupSymbolInModule<LLVM::LLVMFuncOp>((*this)->getParentOp(),
1172                                                 global_name());
1173 }
1174 
1175 static LogicalResult verify(AddressOfOp op) {
1176   auto global = op.getGlobal();
1177   auto function = op.getFunction();
1178   if (!global && !function)
1179     return op.emitOpError(
1180         "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'");
1181 
1182   if (global &&
1183       LLVM::LLVMPointerType::get(global.getType(), global.addr_space()) !=
1184           op.getResult().getType())
1185     return op.emitOpError(
1186         "the type must be a pointer to the type of the referenced global");
1187 
1188   if (function && LLVM::LLVMPointerType::get(function.getType()) !=
1189                       op.getResult().getType())
1190     return op.emitOpError(
1191         "the type must be a pointer to the type of the referenced function");
1192 
1193   return success();
1194 }
1195 
1196 //===----------------------------------------------------------------------===//
1197 // Builder, printer and verifier for LLVM::GlobalOp.
1198 //===----------------------------------------------------------------------===//
1199 
1200 /// Returns the name used for the linkage attribute. This *must* correspond to
1201 /// the name of the attribute in ODS.
1202 static StringRef getLinkageAttrName() { return "linkage"; }
1203 
1204 void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
1205                      bool isConstant, Linkage linkage, StringRef name,
1206                      Attribute value, unsigned addrSpace,
1207                      ArrayRef<NamedAttribute> attrs) {
1208   result.addAttribute(SymbolTable::getSymbolAttrName(),
1209                       builder.getStringAttr(name));
1210   result.addAttribute("type", TypeAttr::get(type));
1211   if (isConstant)
1212     result.addAttribute("constant", builder.getUnitAttr());
1213   if (value)
1214     result.addAttribute("value", value);
1215   result.addAttribute(getLinkageAttrName(),
1216                       builder.getI64IntegerAttr(static_cast<int64_t>(linkage)));
1217   if (addrSpace != 0)
1218     result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace));
1219   result.attributes.append(attrs.begin(), attrs.end());
1220   result.addRegion();
1221 }
1222 
1223 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
1224   p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' ';
1225   if (op.constant())
1226     p << "constant ";
1227   p.printSymbolName(op.sym_name());
1228   p << '(';
1229   if (auto value = op.getValueOrNull())
1230     p.printAttribute(value);
1231   p << ')';
1232   p.printOptionalAttrDict(op.getAttrs(),
1233                           {SymbolTable::getSymbolAttrName(), "type", "constant",
1234                            "value", getLinkageAttrName()});
1235 
1236   // Print the trailing type unless it's a string global.
1237   if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
1238     return;
1239   p << " : " << op.type();
1240 
1241   Region &initializer = op.getInitializerRegion();
1242   if (!initializer.empty())
1243     p.printRegion(initializer, /*printEntryBlockArgs=*/false);
1244 }
1245 
1246 //===----------------------------------------------------------------------===//
1247 // Verifier for LLVM::DialectCastOp.
1248 //===----------------------------------------------------------------------===//
1249 
1250 /// Checks if `llvmType` is dialect cast-compatible with `index` type. Does not
1251 /// report the error, the user is expected to produce an appropriate message.
1252 // TODO: make the size depend on data layout rather than on the conversion
1253 // pass option, and pull that information here.
1254 static LogicalResult verifyCastWithIndex(Type llvmType) {
1255   return success(llvmType.isa<IntegerType>());
1256 }
1257 
1258 /// Checks if `llvmType` is dialect cast-compatible with built-in `type` and
1259 /// reports errors to the location of `op`. `isElement` indicates whether the
1260 /// verification is performed for types that are element types inside a
1261 /// container; we don't want casts from X to X at the top level, but c1<X> to
1262 /// c2<X> may be fine.
1263 static LogicalResult verifyCast(DialectCastOp op, Type llvmType, Type type,
1264                                 bool isElement = false) {
1265   // Equal element types are directly compatible.
1266   if (isElement && llvmType == type)
1267     return success();
1268 
1269   // Index is compatible with any integer.
1270   if (type.isIndex()) {
1271     if (succeeded(verifyCastWithIndex(llvmType)))
1272       return success();
1273 
1274     return op.emitOpError("invalid cast between index and non-integer type");
1275   }
1276 
1277   if (type.isa<IntegerType>()) {
1278     auto llvmIntegerType = llvmType.dyn_cast<IntegerType>();
1279     if (!llvmIntegerType)
1280       return op->emitOpError("invalid cast between integer and non-integer");
1281     if (llvmIntegerType.getWidth() != type.getIntOrFloatBitWidth())
1282       return op.emitOpError("invalid cast changing integer width");
1283     return success();
1284   }
1285 
1286   // Vectors are compatible if they are 1D non-scalable, and their element types
1287   // are compatible. nD vectors are compatible with (n-1)D arrays containing 1D
1288   // vector.
1289   if (auto vectorType = type.dyn_cast<VectorType>()) {
1290     if (vectorType == llvmType && !isElement)
1291       return op.emitOpError("vector types should not be casted");
1292 
1293     if (vectorType.getRank() == 1) {
1294       auto llvmVectorType = llvmType.dyn_cast<VectorType>();
1295       if (!llvmVectorType || llvmVectorType.getRank() != 1)
1296         return op.emitOpError("invalid cast for vector types");
1297 
1298       return verifyCast(op, llvmVectorType.getElementType(),
1299                         vectorType.getElementType(), /*isElement=*/true);
1300     }
1301 
1302     auto arrayType = llvmType.dyn_cast<LLVM::LLVMArrayType>();
1303     if (!arrayType ||
1304         arrayType.getNumElements() != vectorType.getShape().front())
1305       return op.emitOpError("invalid cast for vector, expected array");
1306     return verifyCast(op, arrayType.getElementType(),
1307                       VectorType::get(vectorType.getShape().drop_front(),
1308                                       vectorType.getElementType()),
1309                       /*isElement=*/true);
1310   }
1311 
1312   if (auto memrefType = type.dyn_cast<MemRefType>()) {
1313     // Bare pointer convention: statically-shaped memref is compatible with an
1314     // LLVM pointer to the element type.
1315     if (auto ptrType = llvmType.dyn_cast<LLVMPointerType>()) {
1316       if (!memrefType.hasStaticShape())
1317         return op->emitOpError(
1318             "unexpected bare pointer for dynamically shaped memref");
1319       if (memrefType.getMemorySpace() != ptrType.getAddressSpace())
1320         return op->emitError("invalid conversion between memref and pointer in "
1321                              "different memory spaces");
1322 
1323       return verifyCast(op, ptrType.getElementType(),
1324                         memrefType.getElementType(), /*isElement=*/true);
1325     }
1326 
1327     // Otherwise, memrefs are convertible to a descriptor, which is a structure
1328     // type.
1329     auto structType = llvmType.dyn_cast<LLVMStructType>();
1330     if (!structType)
1331       return op->emitOpError("invalid cast between a memref and a type other "
1332                              "than pointer or memref descriptor");
1333 
1334     unsigned expectedNumElements = memrefType.getRank() == 0 ? 3 : 5;
1335     if (structType.getBody().size() != expectedNumElements) {
1336       return op->emitOpError() << "expected memref descriptor with "
1337                                << expectedNumElements << " elements";
1338     }
1339 
1340     // The first two elements are pointers to the element type.
1341     auto allocatedPtr = structType.getBody()[0].dyn_cast<LLVMPointerType>();
1342     if (!allocatedPtr ||
1343         allocatedPtr.getAddressSpace() != memrefType.getMemorySpace())
1344       return op->emitOpError("expected first element of a memref descriptor to "
1345                              "be a pointer in the address space of the memref");
1346     if (failed(verifyCast(op, allocatedPtr.getElementType(),
1347                           memrefType.getElementType(), /*isElement=*/true)))
1348       return failure();
1349 
1350     auto alignedPtr = structType.getBody()[1].dyn_cast<LLVMPointerType>();
1351     if (!alignedPtr ||
1352         alignedPtr.getAddressSpace() != memrefType.getMemorySpace())
1353       return op->emitOpError(
1354           "expected second element of a memref descriptor to "
1355           "be a pointer in the address space of the memref");
1356     if (failed(verifyCast(op, alignedPtr.getElementType(),
1357                           memrefType.getElementType(), /*isElement=*/true)))
1358       return failure();
1359 
1360     // The second element (offset) is an equivalent of index.
1361     if (failed(verifyCastWithIndex(structType.getBody()[2])))
1362       return op->emitOpError("expected third element of a memref descriptor to "
1363                              "be index-compatible integers");
1364 
1365     // 0D memrefs don't have sizes/strides.
1366     if (memrefType.getRank() == 0)
1367       return success();
1368 
1369     // Sizes and strides are rank-sized arrays of `index` equivalents.
1370     auto sizes = structType.getBody()[3].dyn_cast<LLVMArrayType>();
1371     if (!sizes || failed(verifyCastWithIndex(sizes.getElementType())) ||
1372         sizes.getNumElements() != memrefType.getRank())
1373       return op->emitOpError(
1374           "expected fourth element of a memref descriptor "
1375           "to be an array of <rank> index-compatible integers");
1376 
1377     auto strides = structType.getBody()[4].dyn_cast<LLVMArrayType>();
1378     if (!strides || failed(verifyCastWithIndex(strides.getElementType())) ||
1379         strides.getNumElements() != memrefType.getRank())
1380       return op->emitOpError(
1381           "expected fifth element of a memref descriptor "
1382           "to be an array of <rank> index-compatible integers");
1383 
1384     return success();
1385   }
1386 
1387   // Unranked memrefs are compatible with their descriptors.
1388   if (auto unrankedMemrefType = type.dyn_cast<UnrankedMemRefType>()) {
1389     auto structType = llvmType.dyn_cast<LLVMStructType>();
1390     if (!structType || structType.getBody().size() != 2)
1391       return op->emitOpError(
1392           "expected descriptor to be a struct with two elements");
1393 
1394     if (failed(verifyCastWithIndex(structType.getBody()[0])))
1395       return op->emitOpError("expected first element of a memref descriptor to "
1396                              "be an index-compatible integer");
1397 
1398     auto ptrType = structType.getBody()[1].dyn_cast<LLVMPointerType>();
1399     auto ptrElementType =
1400         ptrType ? ptrType.getElementType().dyn_cast<IntegerType>() : nullptr;
1401     if (!ptrElementType || ptrElementType.getWidth() != 8)
1402       return op->emitOpError("expected second element of a memref descriptor "
1403                              "to be an !llvm.ptr<i8>");
1404 
1405     return success();
1406   }
1407 
1408   // Complex types are compatible with the two-element structs.
1409   if (auto complexType = type.dyn_cast<ComplexType>()) {
1410     auto structType = llvmType.dyn_cast<LLVMStructType>();
1411     if (!structType || structType.getBody().size() != 2 ||
1412         structType.getBody()[0] != structType.getBody()[1] ||
1413         structType.getBody()[0] != complexType.getElementType())
1414       return op->emitOpError("expected 'complex' to map to two-element struct "
1415                              "with identical element types");
1416     return success();
1417   }
1418 
1419   // Everything else is not supported.
1420   return op->emitError("unsupported cast");
1421 }
1422 
1423 static LogicalResult verify(DialectCastOp op) {
1424   if (isCompatibleType(op.getType()))
1425     return verifyCast(op, op.getType(), op.in().getType());
1426 
1427   if (!isCompatibleType(op.in().getType()))
1428     return op->emitOpError("expected one LLVM type and one built-in type");
1429 
1430   return verifyCast(op, op.in().getType(), op.getType());
1431 }
1432 
1433 // Parses one of the keywords provided in the list `keywords` and returns the
1434 // position of the parsed keyword in the list. If none of the keywords from the
1435 // list is parsed, returns -1.
1436 static int parseOptionalKeywordAlternative(OpAsmParser &parser,
1437                                            ArrayRef<StringRef> keywords) {
1438   for (auto en : llvm::enumerate(keywords)) {
1439     if (succeeded(parser.parseOptionalKeyword(en.value())))
1440       return en.index();
1441   }
1442   return -1;
1443 }
1444 
1445 namespace {
1446 template <typename Ty> struct EnumTraits {};
1447 
1448 #define REGISTER_ENUM_TYPE(Ty)                                                 \
1449   template <> struct EnumTraits<Ty> {                                          \
1450     static StringRef stringify(Ty value) { return stringify##Ty(value); }      \
1451     static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); }         \
1452   }
1453 
1454 REGISTER_ENUM_TYPE(Linkage);
1455 } // end namespace
1456 
1457 template <typename EnumTy>
1458 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser,
1459                                             OperationState &result,
1460                                             StringRef name) {
1461   SmallVector<StringRef, 10> names;
1462   for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i)
1463     names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));
1464 
1465   int index = parseOptionalKeywordAlternative(parser, names);
1466   if (index == -1)
1467     return failure();
1468   result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index));
1469   return success();
1470 }
1471 
1472 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
1473 //               `(` attribute? `)` attribute-list? (`:` type)? region?
1474 //
1475 // The type can be omitted for string attributes, in which case it will be
1476 // inferred from the value of the string as [strlen(value) x i8].
1477 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
1478   if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
1479                                                getLinkageAttrName())))
1480     result.addAttribute(getLinkageAttrName(),
1481                         parser.getBuilder().getI64IntegerAttr(
1482                             static_cast<int64_t>(LLVM::Linkage::External)));
1483 
1484   if (succeeded(parser.parseOptionalKeyword("constant")))
1485     result.addAttribute("constant", parser.getBuilder().getUnitAttr());
1486 
1487   StringAttr name;
1488   if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(),
1489                              result.attributes) ||
1490       parser.parseLParen())
1491     return failure();
1492 
1493   Attribute value;
1494   if (parser.parseOptionalRParen()) {
1495     if (parser.parseAttribute(value, "value", result.attributes) ||
1496         parser.parseRParen())
1497       return failure();
1498   }
1499 
1500   SmallVector<Type, 1> types;
1501   if (parser.parseOptionalAttrDict(result.attributes) ||
1502       parser.parseOptionalColonTypeList(types))
1503     return failure();
1504 
1505   if (types.size() > 1)
1506     return parser.emitError(parser.getNameLoc(), "expected zero or one type");
1507 
1508   Region &initRegion = *result.addRegion();
1509   if (types.empty()) {
1510     if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) {
1511       MLIRContext *context = parser.getBuilder().getContext();
1512       auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8),
1513                                                 strAttr.getValue().size());
1514       types.push_back(arrayType);
1515     } else {
1516       return parser.emitError(parser.getNameLoc(),
1517                               "type can only be omitted for string globals");
1518     }
1519   } else {
1520     OptionalParseResult parseResult =
1521         parser.parseOptionalRegion(initRegion, /*arguments=*/{},
1522                                    /*argTypes=*/{});
1523     if (parseResult.hasValue() && failed(*parseResult))
1524       return failure();
1525   }
1526 
1527   result.addAttribute("type", TypeAttr::get(types[0]));
1528   return success();
1529 }
1530 
1531 static LogicalResult verify(GlobalOp op) {
1532   if (!LLVMPointerType::isValidElementType(op.getType()))
1533     return op.emitOpError(
1534         "expects type to be a valid element type for an LLVM pointer");
1535   if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp()))
1536     return op.emitOpError("must appear at the module level");
1537 
1538   if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) {
1539     auto type = op.getType().dyn_cast<LLVMArrayType>();
1540     IntegerType elementType =
1541         type ? type.getElementType().dyn_cast<IntegerType>() : nullptr;
1542     if (!elementType || elementType.getWidth() != 8 ||
1543         type.getNumElements() != strAttr.getValue().size())
1544       return op.emitOpError(
1545           "requires an i8 array type of the length equal to that of the string "
1546           "attribute");
1547   }
1548 
1549   if (Block *b = op.getInitializerBlock()) {
1550     ReturnOp ret = cast<ReturnOp>(b->getTerminator());
1551     if (ret.operand_type_begin() == ret.operand_type_end())
1552       return op.emitOpError("initializer region cannot return void");
1553     if (*ret.operand_type_begin() != op.getType())
1554       return op.emitOpError("initializer region type ")
1555              << *ret.operand_type_begin() << " does not match global type "
1556              << op.getType();
1557 
1558     if (op.getValueOrNull())
1559       return op.emitOpError("cannot have both initializer value and region");
1560   }
1561   return success();
1562 }
1563 
1564 //===----------------------------------------------------------------------===//
1565 // Printing/parsing for LLVM::ShuffleVectorOp.
1566 //===----------------------------------------------------------------------===//
1567 // Expects vector to be of wrapped LLVM vector type and position to be of
1568 // wrapped LLVM i32 type.
1569 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result,
1570                                   Value v1, Value v2, ArrayAttr mask,
1571                                   ArrayRef<NamedAttribute> attrs) {
1572   auto containerType = v1.getType();
1573   auto vType = LLVM::getFixedVectorType(
1574       LLVM::getVectorElementType(containerType), mask.size());
1575   build(b, result, vType, v1, v2, mask);
1576   result.addAttributes(attrs);
1577 }
1578 
1579 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) {
1580   p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " "
1581     << op.mask();
1582   p.printOptionalAttrDict(op.getAttrs(), {"mask"});
1583   p << " : " << op.v1().getType() << ", " << op.v2().getType();
1584 }
1585 
1586 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
1587 //                 `[` integer-literal (`,` integer-literal)* `]`
1588 //                 attribute-dict? `:` type
1589 static ParseResult parseShuffleVectorOp(OpAsmParser &parser,
1590                                         OperationState &result) {
1591   llvm::SMLoc loc;
1592   OpAsmParser::OperandType v1, v2;
1593   ArrayAttr maskAttr;
1594   Type typeV1, typeV2;
1595   if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) ||
1596       parser.parseComma() || parser.parseOperand(v2) ||
1597       parser.parseAttribute(maskAttr, "mask", result.attributes) ||
1598       parser.parseOptionalAttrDict(result.attributes) ||
1599       parser.parseColonType(typeV1) || parser.parseComma() ||
1600       parser.parseType(typeV2) ||
1601       parser.resolveOperand(v1, typeV1, result.operands) ||
1602       parser.resolveOperand(v2, typeV2, result.operands))
1603     return failure();
1604   if (!LLVM::isCompatibleVectorType(typeV1))
1605     return parser.emitError(
1606         loc, "expected LLVM IR dialect vector type for operand #1");
1607   auto vType = LLVM::getFixedVectorType(LLVM::getVectorElementType(typeV1),
1608                                         maskAttr.size());
1609   result.addTypes(vType);
1610   return success();
1611 }
1612 
1613 //===----------------------------------------------------------------------===//
1614 // Implementations for LLVM::LLVMFuncOp.
1615 //===----------------------------------------------------------------------===//
1616 
1617 // Add the entry block to the function.
1618 Block *LLVMFuncOp::addEntryBlock() {
1619   assert(empty() && "function already has an entry block");
1620   assert(!isVarArg() && "unimplemented: non-external variadic functions");
1621 
1622   auto *entry = new Block;
1623   push_back(entry);
1624 
1625   LLVMFunctionType type = getType();
1626   for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
1627     entry->addArgument(type.getParamType(i));
1628   return entry;
1629 }
1630 
1631 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result,
1632                        StringRef name, Type type, LLVM::Linkage linkage,
1633                        ArrayRef<NamedAttribute> attrs,
1634                        ArrayRef<DictionaryAttr> argAttrs) {
1635   result.addRegion();
1636   result.addAttribute(SymbolTable::getSymbolAttrName(),
1637                       builder.getStringAttr(name));
1638   result.addAttribute("type", TypeAttr::get(type));
1639   result.addAttribute(getLinkageAttrName(),
1640                       builder.getI64IntegerAttr(static_cast<int64_t>(linkage)));
1641   result.attributes.append(attrs.begin(), attrs.end());
1642   if (argAttrs.empty())
1643     return;
1644 
1645   unsigned numInputs = type.cast<LLVMFunctionType>().getNumParams();
1646   assert(numInputs == argAttrs.size() &&
1647          "expected as many argument attribute lists as arguments");
1648   SmallString<8> argAttrName;
1649   for (unsigned i = 0; i < numInputs; ++i)
1650     if (DictionaryAttr argDict = argAttrs[i])
1651       result.addAttribute(getArgAttrName(i, argAttrName), argDict);
1652 }
1653 
1654 // Builds an LLVM function type from the given lists of input and output types.
1655 // Returns a null type if any of the types provided are non-LLVM types, or if
1656 // there is more than one output type.
1657 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
1658                                   ArrayRef<Type> inputs, ArrayRef<Type> outputs,
1659                                   impl::VariadicFlag variadicFlag) {
1660   Builder &b = parser.getBuilder();
1661   if (outputs.size() > 1) {
1662     parser.emitError(loc, "failed to construct function type: expected zero or "
1663                           "one function result");
1664     return {};
1665   }
1666 
1667   // Convert inputs to LLVM types, exit early on error.
1668   SmallVector<Type, 4> llvmInputs;
1669   for (auto t : inputs) {
1670     if (!isCompatibleType(t)) {
1671       parser.emitError(loc, "failed to construct function type: expected LLVM "
1672                             "type for function arguments");
1673       return {};
1674     }
1675     llvmInputs.push_back(t);
1676   }
1677 
1678   // No output is denoted as "void" in LLVM type system.
1679   Type llvmOutput =
1680       outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front();
1681   if (!isCompatibleType(llvmOutput)) {
1682     parser.emitError(loc, "failed to construct function type: expected LLVM "
1683                           "type for function results")
1684         << llvmOutput;
1685     return {};
1686   }
1687   return LLVMFunctionType::get(llvmOutput, llvmInputs,
1688                                variadicFlag.isVariadic());
1689 }
1690 
1691 // Parses an LLVM function.
1692 //
1693 // operation ::= `llvm.func` linkage? function-signature function-attributes?
1694 //               function-body
1695 //
1696 static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
1697                                    OperationState &result) {
1698   // Default to external linkage if no keyword is provided.
1699   if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
1700                                                getLinkageAttrName())))
1701     result.addAttribute(getLinkageAttrName(),
1702                         parser.getBuilder().getI64IntegerAttr(
1703                             static_cast<int64_t>(LLVM::Linkage::External)));
1704 
1705   StringAttr nameAttr;
1706   SmallVector<OpAsmParser::OperandType, 8> entryArgs;
1707   SmallVector<NamedAttrList, 1> argAttrs;
1708   SmallVector<NamedAttrList, 1> resultAttrs;
1709   SmallVector<Type, 8> argTypes;
1710   SmallVector<Type, 4> resultTypes;
1711   bool isVariadic;
1712 
1713   auto signatureLocation = parser.getCurrentLocation();
1714   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1715                              result.attributes) ||
1716       impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs,
1717                                    argTypes, argAttrs, isVariadic, resultTypes,
1718                                    resultAttrs))
1719     return failure();
1720 
1721   auto type =
1722       buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
1723                             impl::VariadicFlag(isVariadic));
1724   if (!type)
1725     return failure();
1726   result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type));
1727 
1728   if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
1729     return failure();
1730   impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs,
1731                              resultAttrs);
1732 
1733   auto *body = result.addRegion();
1734   OptionalParseResult parseResult = parser.parseOptionalRegion(
1735       *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
1736   return failure(parseResult.hasValue() && failed(*parseResult));
1737 }
1738 
1739 // Print the LLVMFuncOp. Collects argument and result types and passes them to
1740 // helper functions. Drops "void" result since it cannot be parsed back. Skips
1741 // the external linkage since it is the default value.
1742 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
1743   p << op.getOperationName() << ' ';
1744   if (op.linkage() != LLVM::Linkage::External)
1745     p << stringifyLinkage(op.linkage()) << ' ';
1746   p.printSymbolName(op.getName());
1747 
1748   LLVMFunctionType fnType = op.getType();
1749   SmallVector<Type, 8> argTypes;
1750   SmallVector<Type, 1> resTypes;
1751   argTypes.reserve(fnType.getNumParams());
1752   for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i)
1753     argTypes.push_back(fnType.getParamType(i));
1754 
1755   Type returnType = fnType.getReturnType();
1756   if (!returnType.isa<LLVMVoidType>())
1757     resTypes.push_back(returnType);
1758 
1759   impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes);
1760   impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(),
1761                                 {getLinkageAttrName()});
1762 
1763   // Print the body if this is not an external function.
1764   Region &body = op.body();
1765   if (!body.empty())
1766     p.printRegion(body, /*printEntryBlockArgs=*/false,
1767                   /*printBlockTerminators=*/true);
1768 }
1769 
1770 // Hook for OpTrait::FunctionLike, called after verifying that the 'type'
1771 // attribute is present.  This can check for preconditions of the
1772 // getNumArguments hook not failing.
1773 LogicalResult LLVMFuncOp::verifyType() {
1774   auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMFunctionType>();
1775   if (!llvmType)
1776     return emitOpError("requires '" + getTypeAttrName() +
1777                        "' attribute of wrapped LLVM function type");
1778 
1779   return success();
1780 }
1781 
1782 // Hook for OpTrait::FunctionLike, returns the number of function arguments.
1783 // Depends on the type attribute being correct as checked by verifyType
1784 unsigned LLVMFuncOp::getNumFuncArguments() { return getType().getNumParams(); }
1785 
1786 // Hook for OpTrait::FunctionLike, returns the number of function results.
1787 // Depends on the type attribute being correct as checked by verifyType
1788 unsigned LLVMFuncOp::getNumFuncResults() {
1789   // We model LLVM functions that return void as having zero results,
1790   // and all others as having one result.
1791   // If we modeled a void return as one result, then it would be possible to
1792   // attach an MLIR result attribute to it, and it isn't clear what semantics we
1793   // would assign to that.
1794   if (getType().getReturnType().isa<LLVMVoidType>())
1795     return 0;
1796   return 1;
1797 }
1798 
1799 // Verifies LLVM- and implementation-specific properties of the LLVM func Op:
1800 // - functions don't have 'common' linkage
1801 // - external functions have 'external' or 'extern_weak' linkage;
1802 // - vararg is (currently) only supported for external functions;
1803 // - entry block arguments are of LLVM types and match the function signature.
1804 static LogicalResult verify(LLVMFuncOp op) {
1805   if (op.linkage() == LLVM::Linkage::Common)
1806     return op.emitOpError()
1807            << "functions cannot have '"
1808            << stringifyLinkage(LLVM::Linkage::Common) << "' linkage";
1809 
1810   if (op.isExternal()) {
1811     if (op.linkage() != LLVM::Linkage::External &&
1812         op.linkage() != LLVM::Linkage::ExternWeak)
1813       return op.emitOpError()
1814              << "external functions must have '"
1815              << stringifyLinkage(LLVM::Linkage::External) << "' or '"
1816              << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage";
1817     return success();
1818   }
1819 
1820   if (op.isVarArg())
1821     return op.emitOpError("only external functions can be variadic");
1822 
1823   unsigned numArguments = op.getType().getNumParams();
1824   Block &entryBlock = op.front();
1825   for (unsigned i = 0; i < numArguments; ++i) {
1826     Type argType = entryBlock.getArgument(i).getType();
1827     if (!isCompatibleType(argType))
1828       return op.emitOpError("entry block argument #")
1829              << i << " is not of LLVM type";
1830     if (op.getType().getParamType(i) != argType)
1831       return op.emitOpError("the type of entry block argument #")
1832              << i << " does not match the function signature";
1833   }
1834 
1835   return success();
1836 }
1837 
1838 //===----------------------------------------------------------------------===//
1839 // Verification for LLVM::ConstantOp.
1840 //===----------------------------------------------------------------------===//
1841 
1842 static LogicalResult verify(LLVM::ConstantOp op) {
1843   if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() ||
1844         op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>()))
1845     return op.emitOpError()
1846            << "only supports integer, float, string or elements attributes";
1847   return success();
1848 }
1849 
1850 //===----------------------------------------------------------------------===//
1851 // Utility functions for parsing atomic ops
1852 //===----------------------------------------------------------------------===//
1853 
1854 // Helper function to parse a keyword into the specified attribute named by
1855 // `attrName`. The keyword must match one of the string values defined by the
1856 // AtomicBinOp enum. The resulting I64 attribute is added to the `result`
1857 // state.
1858 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result,
1859                                     StringRef attrName) {
1860   llvm::SMLoc loc;
1861   StringRef keyword;
1862   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword))
1863     return failure();
1864 
1865   // Replace the keyword `keyword` with an integer attribute.
1866   auto kind = symbolizeAtomicBinOp(keyword);
1867   if (!kind) {
1868     return parser.emitError(loc)
1869            << "'" << keyword << "' is an incorrect value of the '" << attrName
1870            << "' attribute";
1871   }
1872 
1873   auto value = static_cast<int64_t>(kind.getValue());
1874   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1875   result.addAttribute(attrName, attr);
1876 
1877   return success();
1878 }
1879 
1880 // Helper function to parse a keyword into the specified attribute named by
1881 // `attrName`. The keyword must match one of the string values defined by the
1882 // AtomicOrdering enum. The resulting I64 attribute is added to the `result`
1883 // state.
1884 static ParseResult parseAtomicOrdering(OpAsmParser &parser,
1885                                        OperationState &result,
1886                                        StringRef attrName) {
1887   llvm::SMLoc loc;
1888   StringRef ordering;
1889   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering))
1890     return failure();
1891 
1892   // Replace the keyword `ordering` with an integer attribute.
1893   auto kind = symbolizeAtomicOrdering(ordering);
1894   if (!kind) {
1895     return parser.emitError(loc)
1896            << "'" << ordering << "' is an incorrect value of the '" << attrName
1897            << "' attribute";
1898   }
1899 
1900   auto value = static_cast<int64_t>(kind.getValue());
1901   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1902   result.addAttribute(attrName, attr);
1903 
1904   return success();
1905 }
1906 
1907 //===----------------------------------------------------------------------===//
1908 // Printer, parser and verifier for LLVM::AtomicRMWOp.
1909 //===----------------------------------------------------------------------===//
1910 
1911 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) {
1912   p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' '
1913     << op.ptr() << ", " << op.val() << ' '
1914     << stringifyAtomicOrdering(op.ordering()) << ' ';
1915   p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"});
1916   p << " : " << op.res().getType();
1917 }
1918 
1919 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword
1920 //                 attribute-dict? `:` type
1921 static ParseResult parseAtomicRMWOp(OpAsmParser &parser,
1922                                     OperationState &result) {
1923   Type type;
1924   OpAsmParser::OperandType ptr, val;
1925   if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) ||
1926       parser.parseComma() || parser.parseOperand(val) ||
1927       parseAtomicOrdering(parser, result, "ordering") ||
1928       parser.parseOptionalAttrDict(result.attributes) ||
1929       parser.parseColonType(type) ||
1930       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
1931                             result.operands) ||
1932       parser.resolveOperand(val, type, result.operands))
1933     return failure();
1934 
1935   result.addTypes(type);
1936   return success();
1937 }
1938 
1939 static LogicalResult verify(AtomicRMWOp op) {
1940   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
1941   auto valType = op.val().getType();
1942   if (valType != ptrType.getElementType())
1943     return op.emitOpError("expected LLVM IR element type for operand #0 to "
1944                           "match type for operand #1");
1945   auto resType = op.res().getType();
1946   if (resType != valType)
1947     return op.emitOpError(
1948         "expected LLVM IR result type to match type for operand #1");
1949   if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) {
1950     if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
1951       return op.emitOpError("expected LLVM IR floating point type");
1952   } else if (op.bin_op() == AtomicBinOp::xchg) {
1953     auto intType = valType.dyn_cast<IntegerType>();
1954     unsigned intBitWidth = intType ? intType.getWidth() : 0;
1955     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
1956         intBitWidth != 64 && !valType.isa<BFloat16Type>() &&
1957         !valType.isa<Float16Type>() && !valType.isa<Float32Type>() &&
1958         !valType.isa<Float64Type>())
1959       return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
1960   } else {
1961     auto intType = valType.dyn_cast<IntegerType>();
1962     unsigned intBitWidth = intType ? intType.getWidth() : 0;
1963     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
1964         intBitWidth != 64)
1965       return op.emitOpError("expected LLVM IR integer type");
1966   }
1967   return success();
1968 }
1969 
1970 //===----------------------------------------------------------------------===//
1971 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp.
1972 //===----------------------------------------------------------------------===//
1973 
1974 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) {
1975   p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", "
1976     << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' '
1977     << stringifyAtomicOrdering(op.failure_ordering());
1978   p.printOptionalAttrDict(op.getAttrs(),
1979                           {"success_ordering", "failure_ordering"});
1980   p << " : " << op.val().getType();
1981 }
1982 
1983 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use
1984 //                 keyword keyword attribute-dict? `:` type
1985 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser,
1986                                         OperationState &result) {
1987   auto &builder = parser.getBuilder();
1988   Type type;
1989   OpAsmParser::OperandType ptr, cmp, val;
1990   if (parser.parseOperand(ptr) || parser.parseComma() ||
1991       parser.parseOperand(cmp) || parser.parseComma() ||
1992       parser.parseOperand(val) ||
1993       parseAtomicOrdering(parser, result, "success_ordering") ||
1994       parseAtomicOrdering(parser, result, "failure_ordering") ||
1995       parser.parseOptionalAttrDict(result.attributes) ||
1996       parser.parseColonType(type) ||
1997       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
1998                             result.operands) ||
1999       parser.resolveOperand(cmp, type, result.operands) ||
2000       parser.resolveOperand(val, type, result.operands))
2001     return failure();
2002 
2003   auto boolType = IntegerType::get(builder.getContext(), 1);
2004   auto resultType =
2005       LLVMStructType::getLiteral(builder.getContext(), {type, boolType});
2006   result.addTypes(resultType);
2007 
2008   return success();
2009 }
2010 
2011 static LogicalResult verify(AtomicCmpXchgOp op) {
2012   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
2013   if (!ptrType)
2014     return op.emitOpError("expected LLVM IR pointer type for operand #0");
2015   auto cmpType = op.cmp().getType();
2016   auto valType = op.val().getType();
2017   if (cmpType != ptrType.getElementType() || cmpType != valType)
2018     return op.emitOpError("expected LLVM IR element type for operand #0 to "
2019                           "match type for all other operands");
2020   auto intType = valType.dyn_cast<IntegerType>();
2021   unsigned intBitWidth = intType ? intType.getWidth() : 0;
2022   if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 &&
2023       intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 &&
2024       !valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() &&
2025       !valType.isa<Float32Type>() && !valType.isa<Float64Type>())
2026     return op.emitOpError("unexpected LLVM IR type");
2027   if (op.success_ordering() < AtomicOrdering::monotonic ||
2028       op.failure_ordering() < AtomicOrdering::monotonic)
2029     return op.emitOpError("ordering must be at least 'monotonic'");
2030   if (op.failure_ordering() == AtomicOrdering::release ||
2031       op.failure_ordering() == AtomicOrdering::acq_rel)
2032     return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
2033   return success();
2034 }
2035 
2036 //===----------------------------------------------------------------------===//
2037 // Printer, parser and verifier for LLVM::FenceOp.
2038 //===----------------------------------------------------------------------===//
2039 
2040 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword
2041 // attribute-dict?
2042 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) {
2043   StringAttr sScope;
2044   StringRef syncscopeKeyword = "syncscope";
2045   if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) {
2046     if (parser.parseLParen() ||
2047         parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) ||
2048         parser.parseRParen())
2049       return failure();
2050   } else {
2051     result.addAttribute(syncscopeKeyword,
2052                         parser.getBuilder().getStringAttr(""));
2053   }
2054   if (parseAtomicOrdering(parser, result, "ordering") ||
2055       parser.parseOptionalAttrDict(result.attributes))
2056     return failure();
2057   return success();
2058 }
2059 
2060 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) {
2061   StringRef syncscopeKeyword = "syncscope";
2062   p << op.getOperationName() << ' ';
2063   if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty())
2064     p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") ";
2065   p << stringifyAtomicOrdering(op.ordering());
2066 }
2067 
2068 static LogicalResult verify(FenceOp &op) {
2069   if (op.ordering() == AtomicOrdering::not_atomic ||
2070       op.ordering() == AtomicOrdering::unordered ||
2071       op.ordering() == AtomicOrdering::monotonic)
2072     return op.emitOpError("can be given only acquire, release, acq_rel, "
2073                           "and seq_cst orderings");
2074   return success();
2075 }
2076 
2077 //===----------------------------------------------------------------------===//
2078 // LLVMDialect initialization, type parsing, and registration.
2079 //===----------------------------------------------------------------------===//
2080 
2081 void LLVMDialect::initialize() {
2082   addAttributes<FMFAttr>();
2083 
2084   // clang-format off
2085   addTypes<LLVMVoidType,
2086            LLVMPPCFP128Type,
2087            LLVMX86MMXType,
2088            LLVMTokenType,
2089            LLVMLabelType,
2090            LLVMMetadataType,
2091            LLVMFunctionType,
2092            LLVMPointerType,
2093            LLVMFixedVectorType,
2094            LLVMScalableVectorType,
2095            LLVMArrayType,
2096            LLVMStructType>();
2097   // clang-format on
2098   addOperations<
2099 #define GET_OP_LIST
2100 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2101       >();
2102 
2103   // Support unknown operations because not all LLVM operations are registered.
2104   allowUnknownOperations();
2105 }
2106 
2107 #define GET_OP_CLASSES
2108 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2109 
2110 /// Parse a type registered to this dialect.
2111 Type LLVMDialect::parseType(DialectAsmParser &parser) const {
2112   return detail::parseType(parser);
2113 }
2114 
2115 /// Print a type registered to this dialect.
2116 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
2117   return detail::printType(type, os);
2118 }
2119 
2120 LogicalResult LLVMDialect::verifyDataLayoutString(
2121     StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
2122   llvm::Expected<llvm::DataLayout> maybeDataLayout =
2123       llvm::DataLayout::parse(descr);
2124   if (maybeDataLayout)
2125     return success();
2126 
2127   std::string message;
2128   llvm::raw_string_ostream messageStream(message);
2129   llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
2130   reportError("invalid data layout descriptor: " + messageStream.str());
2131   return failure();
2132 }
2133 
2134 /// Verify LLVM dialect attributes.
2135 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
2136                                                     NamedAttribute attr) {
2137   // If the data layout attribute is present, it must use the LLVM data layout
2138   // syntax. Try parsing it and report errors in case of failure. Users of this
2139   // attribute may assume it is well-formed and can pass it to the (asserting)
2140   // llvm::DataLayout constructor.
2141   if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName())
2142     return success();
2143   if (auto stringAttr = attr.second.dyn_cast<StringAttr>())
2144     return verifyDataLayoutString(
2145         stringAttr.getValue(),
2146         [op](const Twine &message) { op->emitOpError() << message.str(); });
2147 
2148   return op->emitOpError() << "expected '"
2149                            << LLVM::LLVMDialect::getDataLayoutAttrName()
2150                            << "' to be a string attribute";
2151 }
2152 
2153 /// Verify LLVMIR function argument attributes.
2154 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
2155                                                     unsigned regionIdx,
2156                                                     unsigned argIdx,
2157                                                     NamedAttribute argAttr) {
2158   // Check that llvm.noalias is a boolean attribute.
2159   if (argAttr.first == LLVMDialect::getNoAliasAttrName() &&
2160       !argAttr.second.isa<BoolAttr>())
2161     return op->emitError()
2162            << "llvm.noalias argument attribute of non boolean type";
2163   // Check that llvm.align is an integer attribute.
2164   if (argAttr.first == LLVMDialect::getAlignAttrName() &&
2165       !argAttr.second.isa<IntegerAttr>())
2166     return op->emitError()
2167            << "llvm.align argument attribute of non integer type";
2168   return success();
2169 }
2170 
2171 //===----------------------------------------------------------------------===//
2172 // Utility functions.
2173 //===----------------------------------------------------------------------===//
2174 
2175 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
2176                                      StringRef name, StringRef value,
2177                                      LLVM::Linkage linkage) {
2178   assert(builder.getInsertionBlock() &&
2179          builder.getInsertionBlock()->getParentOp() &&
2180          "expected builder to point to a block constrained in an op");
2181   auto module =
2182       builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
2183   assert(module && "builder points to an op outside of a module");
2184 
2185   // Create the global at the entry of the module.
2186   OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener());
2187   MLIRContext *ctx = builder.getContext();
2188   auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size());
2189   auto global = moduleBuilder.create<LLVM::GlobalOp>(
2190       loc, type, /*isConstant=*/true, linkage, name,
2191       builder.getStringAttr(value));
2192 
2193   // Get the pointer to the first character in the global string.
2194   Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
2195   Value cst0 = builder.create<LLVM::ConstantOp>(
2196       loc, IntegerType::get(ctx, 64),
2197       builder.getIntegerAttr(builder.getIndexType(), 0));
2198   return builder.create<LLVM::GEPOp>(
2199       loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr,
2200       ValueRange{cst0, cst0});
2201 }
2202 
2203 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
2204   return op->hasTrait<OpTrait::SymbolTable>() &&
2205          op->hasTrait<OpTrait::IsIsolatedFromAbove>();
2206 }
2207 
2208 FMFAttr FMFAttr::get(FastmathFlags flags, MLIRContext *context) {
2209   return Base::get(context, static_cast<uint64_t>(flags));
2210 }
2211 
2212 FastmathFlags FMFAttr::getFlags() const {
2213   return static_cast<FastmathFlags>(getImpl()->value);
2214 }
2215 
2216 static constexpr const FastmathFlags FastmathFlagsList[] = {
2217     // clang-format off
2218     FastmathFlags::nnan,
2219     FastmathFlags::ninf,
2220     FastmathFlags::nsz,
2221     FastmathFlags::arcp,
2222     FastmathFlags::contract,
2223     FastmathFlags::afn,
2224     FastmathFlags::reassoc,
2225     FastmathFlags::fast,
2226     // clang-format on
2227 };
2228 
2229 void FMFAttr::print(DialectAsmPrinter &printer) const {
2230   printer << "fastmath<";
2231   auto flags = llvm::make_filter_range(FastmathFlagsList, [&](auto flag) {
2232     return bitEnumContains(this->getFlags(), flag);
2233   });
2234   llvm::interleaveComma(flags, printer,
2235                         [&](auto flag) { printer << stringifyEnum(flag); });
2236   printer << ">";
2237 }
2238 
2239 Attribute FMFAttr::parse(DialectAsmParser &parser) {
2240   if (failed(parser.parseLess()))
2241     return {};
2242 
2243   FastmathFlags flags = {};
2244   if (failed(parser.parseOptionalGreater())) {
2245     do {
2246       StringRef elemName;
2247       if (failed(parser.parseKeyword(&elemName)))
2248         return {};
2249 
2250       auto elem = symbolizeFastmathFlags(elemName);
2251       if (!elem) {
2252         parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ")
2253             << elemName;
2254         return {};
2255       }
2256 
2257       flags = flags | *elem;
2258     } while (succeeded(parser.parseOptionalComma()));
2259 
2260     if (failed(parser.parseGreater()))
2261       return {};
2262   }
2263 
2264   return FMFAttr::get(flags, parser.getBuilder().getContext());
2265 }
2266 
2267 Attribute LLVMDialect::parseAttribute(DialectAsmParser &parser,
2268                                       Type type) const {
2269   if (type) {
2270     parser.emitError(parser.getNameLoc(), "unexpected type");
2271     return {};
2272   }
2273   StringRef attrKind;
2274   if (parser.parseKeyword(&attrKind))
2275     return {};
2276 
2277   if (attrKind == "fastmath")
2278     return FMFAttr::parse(parser);
2279 
2280   parser.emitError(parser.getNameLoc(), "Unknown attrribute type: ")
2281       << attrKind;
2282   return {};
2283 }
2284 
2285 void LLVMDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
2286   if (auto fmf = attr.dyn_cast<FMFAttr>())
2287     fmf.print(os);
2288   else
2289     llvm_unreachable("Unknown attribute type");
2290 }
2291