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   // Vectors are compatible if they are 1D non-scalable, and their element types
1278   // are compatible.
1279   if (auto vectorType = type.dyn_cast<VectorType>())
1280     return op.emitOpError("vector types should not be casted");
1281 
1282   if (auto memrefType = type.dyn_cast<MemRefType>()) {
1283     // Bare pointer convention: statically-shaped memref is compatible with an
1284     // LLVM pointer to the element type.
1285     if (auto ptrType = llvmType.dyn_cast<LLVMPointerType>()) {
1286       if (!memrefType.hasStaticShape())
1287         return op->emitOpError(
1288             "unexpected bare pointer for dynamically shaped memref");
1289       if (memrefType.getMemorySpace() != ptrType.getAddressSpace())
1290         return op->emitError("invalid conversion between memref and pointer in "
1291                              "different memory spaces");
1292 
1293       return verifyCast(op, ptrType.getElementType(),
1294                         memrefType.getElementType(), /*isElement=*/true);
1295     }
1296 
1297     // Otherwise, memrefs are convertible to a descriptor, which is a structure
1298     // type.
1299     auto structType = llvmType.dyn_cast<LLVMStructType>();
1300     if (!structType)
1301       return op->emitOpError("invalid cast between a memref and a type other "
1302                              "than pointer or memref descriptor");
1303 
1304     unsigned expectedNumElements = memrefType.getRank() == 0 ? 3 : 5;
1305     if (structType.getBody().size() != expectedNumElements) {
1306       return op->emitOpError() << "expected memref descriptor with "
1307                                << expectedNumElements << " elements";
1308     }
1309 
1310     // The first two elements are pointers to the element type.
1311     auto allocatedPtr = structType.getBody()[0].dyn_cast<LLVMPointerType>();
1312     if (!allocatedPtr ||
1313         allocatedPtr.getAddressSpace() != memrefType.getMemorySpace())
1314       return op->emitOpError("expected first element of a memref descriptor to "
1315                              "be a pointer in the address space of the memref");
1316     if (failed(verifyCast(op, allocatedPtr.getElementType(),
1317                           memrefType.getElementType(), /*isElement=*/true)))
1318       return failure();
1319 
1320     auto alignedPtr = structType.getBody()[1].dyn_cast<LLVMPointerType>();
1321     if (!alignedPtr ||
1322         alignedPtr.getAddressSpace() != memrefType.getMemorySpace())
1323       return op->emitOpError(
1324           "expected second element of a memref descriptor to "
1325           "be a pointer in the address space of the memref");
1326     if (failed(verifyCast(op, alignedPtr.getElementType(),
1327                           memrefType.getElementType(), /*isElement=*/true)))
1328       return failure();
1329 
1330     // The second element (offset) is an equivalent of index.
1331     if (failed(verifyCastWithIndex(structType.getBody()[2])))
1332       return op->emitOpError("expected third element of a memref descriptor to "
1333                              "be index-compatible integers");
1334 
1335     // 0D memrefs don't have sizes/strides.
1336     if (memrefType.getRank() == 0)
1337       return success();
1338 
1339     // Sizes and strides are rank-sized arrays of `index` equivalents.
1340     auto sizes = structType.getBody()[3].dyn_cast<LLVMArrayType>();
1341     if (!sizes || failed(verifyCastWithIndex(sizes.getElementType())) ||
1342         sizes.getNumElements() != memrefType.getRank())
1343       return op->emitOpError(
1344           "expected fourth element of a memref descriptor "
1345           "to be an array of <rank> index-compatible integers");
1346 
1347     auto strides = structType.getBody()[4].dyn_cast<LLVMArrayType>();
1348     if (!strides || failed(verifyCastWithIndex(strides.getElementType())) ||
1349         strides.getNumElements() != memrefType.getRank())
1350       return op->emitOpError(
1351           "expected fifth element of a memref descriptor "
1352           "to be an array of <rank> index-compatible integers");
1353 
1354     return success();
1355   }
1356 
1357   // Unranked memrefs are compatible with their descriptors.
1358   if (auto unrankedMemrefType = type.dyn_cast<UnrankedMemRefType>()) {
1359     auto structType = llvmType.dyn_cast<LLVMStructType>();
1360     if (!structType || structType.getBody().size() != 2)
1361       return op->emitOpError(
1362           "expected descriptor to be a struct with two elements");
1363 
1364     if (failed(verifyCastWithIndex(structType.getBody()[0])))
1365       return op->emitOpError("expected first element of a memref descriptor to "
1366                              "be an index-compatible integer");
1367 
1368     auto ptrType = structType.getBody()[1].dyn_cast<LLVMPointerType>();
1369     auto ptrElementType =
1370         ptrType ? ptrType.getElementType().dyn_cast<IntegerType>() : nullptr;
1371     if (!ptrElementType || ptrElementType.getWidth() != 8)
1372       return op->emitOpError("expected second element of a memref descriptor "
1373                              "to be an !llvm.ptr<i8>");
1374 
1375     return success();
1376   }
1377 
1378   // Everything else is not supported.
1379   return op->emitError("unsupported cast");
1380 }
1381 
1382 static LogicalResult verify(DialectCastOp op) {
1383   if (isCompatibleType(op.getType()))
1384     return verifyCast(op, op.getType(), op.in().getType());
1385 
1386   if (!isCompatibleType(op.in().getType()))
1387     return op->emitOpError("expected one LLVM type and one built-in type");
1388 
1389   return verifyCast(op, op.in().getType(), op.getType());
1390 }
1391 
1392 // Parses one of the keywords provided in the list `keywords` and returns the
1393 // position of the parsed keyword in the list. If none of the keywords from the
1394 // list is parsed, returns -1.
1395 static int parseOptionalKeywordAlternative(OpAsmParser &parser,
1396                                            ArrayRef<StringRef> keywords) {
1397   for (auto en : llvm::enumerate(keywords)) {
1398     if (succeeded(parser.parseOptionalKeyword(en.value())))
1399       return en.index();
1400   }
1401   return -1;
1402 }
1403 
1404 namespace {
1405 template <typename Ty> struct EnumTraits {};
1406 
1407 #define REGISTER_ENUM_TYPE(Ty)                                                 \
1408   template <> struct EnumTraits<Ty> {                                          \
1409     static StringRef stringify(Ty value) { return stringify##Ty(value); }      \
1410     static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); }         \
1411   }
1412 
1413 REGISTER_ENUM_TYPE(Linkage);
1414 } // end namespace
1415 
1416 template <typename EnumTy>
1417 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser,
1418                                             OperationState &result,
1419                                             StringRef name) {
1420   SmallVector<StringRef, 10> names;
1421   for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i)
1422     names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));
1423 
1424   int index = parseOptionalKeywordAlternative(parser, names);
1425   if (index == -1)
1426     return failure();
1427   result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index));
1428   return success();
1429 }
1430 
1431 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
1432 //               `(` attribute? `)` attribute-list? (`:` type)? region?
1433 //
1434 // The type can be omitted for string attributes, in which case it will be
1435 // inferred from the value of the string as [strlen(value) x i8].
1436 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
1437   if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
1438                                                getLinkageAttrName())))
1439     result.addAttribute(getLinkageAttrName(),
1440                         parser.getBuilder().getI64IntegerAttr(
1441                             static_cast<int64_t>(LLVM::Linkage::External)));
1442 
1443   if (succeeded(parser.parseOptionalKeyword("constant")))
1444     result.addAttribute("constant", parser.getBuilder().getUnitAttr());
1445 
1446   StringAttr name;
1447   if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(),
1448                              result.attributes) ||
1449       parser.parseLParen())
1450     return failure();
1451 
1452   Attribute value;
1453   if (parser.parseOptionalRParen()) {
1454     if (parser.parseAttribute(value, "value", result.attributes) ||
1455         parser.parseRParen())
1456       return failure();
1457   }
1458 
1459   SmallVector<Type, 1> types;
1460   if (parser.parseOptionalAttrDict(result.attributes) ||
1461       parser.parseOptionalColonTypeList(types))
1462     return failure();
1463 
1464   if (types.size() > 1)
1465     return parser.emitError(parser.getNameLoc(), "expected zero or one type");
1466 
1467   Region &initRegion = *result.addRegion();
1468   if (types.empty()) {
1469     if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) {
1470       MLIRContext *context = parser.getBuilder().getContext();
1471       auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8),
1472                                                 strAttr.getValue().size());
1473       types.push_back(arrayType);
1474     } else {
1475       return parser.emitError(parser.getNameLoc(),
1476                               "type can only be omitted for string globals");
1477     }
1478   } else {
1479     OptionalParseResult parseResult =
1480         parser.parseOptionalRegion(initRegion, /*arguments=*/{},
1481                                    /*argTypes=*/{});
1482     if (parseResult.hasValue() && failed(*parseResult))
1483       return failure();
1484   }
1485 
1486   result.addAttribute("type", TypeAttr::get(types[0]));
1487   return success();
1488 }
1489 
1490 static LogicalResult verify(GlobalOp op) {
1491   if (!LLVMPointerType::isValidElementType(op.getType()))
1492     return op.emitOpError(
1493         "expects type to be a valid element type for an LLVM pointer");
1494   if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp()))
1495     return op.emitOpError("must appear at the module level");
1496 
1497   if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) {
1498     auto type = op.getType().dyn_cast<LLVMArrayType>();
1499     IntegerType elementType =
1500         type ? type.getElementType().dyn_cast<IntegerType>() : nullptr;
1501     if (!elementType || elementType.getWidth() != 8 ||
1502         type.getNumElements() != strAttr.getValue().size())
1503       return op.emitOpError(
1504           "requires an i8 array type of the length equal to that of the string "
1505           "attribute");
1506   }
1507 
1508   if (Block *b = op.getInitializerBlock()) {
1509     ReturnOp ret = cast<ReturnOp>(b->getTerminator());
1510     if (ret.operand_type_begin() == ret.operand_type_end())
1511       return op.emitOpError("initializer region cannot return void");
1512     if (*ret.operand_type_begin() != op.getType())
1513       return op.emitOpError("initializer region type ")
1514              << *ret.operand_type_begin() << " does not match global type "
1515              << op.getType();
1516 
1517     if (op.getValueOrNull())
1518       return op.emitOpError("cannot have both initializer value and region");
1519   }
1520   return success();
1521 }
1522 
1523 //===----------------------------------------------------------------------===//
1524 // Printing/parsing for LLVM::ShuffleVectorOp.
1525 //===----------------------------------------------------------------------===//
1526 // Expects vector to be of wrapped LLVM vector type and position to be of
1527 // wrapped LLVM i32 type.
1528 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result,
1529                                   Value v1, Value v2, ArrayAttr mask,
1530                                   ArrayRef<NamedAttribute> attrs) {
1531   auto containerType = v1.getType();
1532   auto vType = LLVM::getFixedVectorType(
1533       LLVM::getVectorElementType(containerType), mask.size());
1534   build(b, result, vType, v1, v2, mask);
1535   result.addAttributes(attrs);
1536 }
1537 
1538 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) {
1539   p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " "
1540     << op.mask();
1541   p.printOptionalAttrDict(op.getAttrs(), {"mask"});
1542   p << " : " << op.v1().getType() << ", " << op.v2().getType();
1543 }
1544 
1545 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
1546 //                 `[` integer-literal (`,` integer-literal)* `]`
1547 //                 attribute-dict? `:` type
1548 static ParseResult parseShuffleVectorOp(OpAsmParser &parser,
1549                                         OperationState &result) {
1550   llvm::SMLoc loc;
1551   OpAsmParser::OperandType v1, v2;
1552   ArrayAttr maskAttr;
1553   Type typeV1, typeV2;
1554   if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) ||
1555       parser.parseComma() || parser.parseOperand(v2) ||
1556       parser.parseAttribute(maskAttr, "mask", result.attributes) ||
1557       parser.parseOptionalAttrDict(result.attributes) ||
1558       parser.parseColonType(typeV1) || parser.parseComma() ||
1559       parser.parseType(typeV2) ||
1560       parser.resolveOperand(v1, typeV1, result.operands) ||
1561       parser.resolveOperand(v2, typeV2, result.operands))
1562     return failure();
1563   if (!LLVM::isCompatibleVectorType(typeV1))
1564     return parser.emitError(
1565         loc, "expected LLVM IR dialect vector type for operand #1");
1566   auto vType = LLVM::getFixedVectorType(LLVM::getVectorElementType(typeV1),
1567                                         maskAttr.size());
1568   result.addTypes(vType);
1569   return success();
1570 }
1571 
1572 //===----------------------------------------------------------------------===//
1573 // Implementations for LLVM::LLVMFuncOp.
1574 //===----------------------------------------------------------------------===//
1575 
1576 // Add the entry block to the function.
1577 Block *LLVMFuncOp::addEntryBlock() {
1578   assert(empty() && "function already has an entry block");
1579   assert(!isVarArg() && "unimplemented: non-external variadic functions");
1580 
1581   auto *entry = new Block;
1582   push_back(entry);
1583 
1584   LLVMFunctionType type = getType();
1585   for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
1586     entry->addArgument(type.getParamType(i));
1587   return entry;
1588 }
1589 
1590 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result,
1591                        StringRef name, Type type, LLVM::Linkage linkage,
1592                        ArrayRef<NamedAttribute> attrs,
1593                        ArrayRef<DictionaryAttr> argAttrs) {
1594   result.addRegion();
1595   result.addAttribute(SymbolTable::getSymbolAttrName(),
1596                       builder.getStringAttr(name));
1597   result.addAttribute("type", TypeAttr::get(type));
1598   result.addAttribute(getLinkageAttrName(),
1599                       builder.getI64IntegerAttr(static_cast<int64_t>(linkage)));
1600   result.attributes.append(attrs.begin(), attrs.end());
1601   if (argAttrs.empty())
1602     return;
1603 
1604   unsigned numInputs = type.cast<LLVMFunctionType>().getNumParams();
1605   assert(numInputs == argAttrs.size() &&
1606          "expected as many argument attribute lists as arguments");
1607   SmallString<8> argAttrName;
1608   for (unsigned i = 0; i < numInputs; ++i)
1609     if (DictionaryAttr argDict = argAttrs[i])
1610       result.addAttribute(getArgAttrName(i, argAttrName), argDict);
1611 }
1612 
1613 // Builds an LLVM function type from the given lists of input and output types.
1614 // Returns a null type if any of the types provided are non-LLVM types, or if
1615 // there is more than one output type.
1616 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
1617                                   ArrayRef<Type> inputs, ArrayRef<Type> outputs,
1618                                   impl::VariadicFlag variadicFlag) {
1619   Builder &b = parser.getBuilder();
1620   if (outputs.size() > 1) {
1621     parser.emitError(loc, "failed to construct function type: expected zero or "
1622                           "one function result");
1623     return {};
1624   }
1625 
1626   // Convert inputs to LLVM types, exit early on error.
1627   SmallVector<Type, 4> llvmInputs;
1628   for (auto t : inputs) {
1629     if (!isCompatibleType(t)) {
1630       parser.emitError(loc, "failed to construct function type: expected LLVM "
1631                             "type for function arguments");
1632       return {};
1633     }
1634     llvmInputs.push_back(t);
1635   }
1636 
1637   // No output is denoted as "void" in LLVM type system.
1638   Type llvmOutput =
1639       outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front();
1640   if (!isCompatibleType(llvmOutput)) {
1641     parser.emitError(loc, "failed to construct function type: expected LLVM "
1642                           "type for function results")
1643         << llvmOutput;
1644     return {};
1645   }
1646   return LLVMFunctionType::get(llvmOutput, llvmInputs,
1647                                variadicFlag.isVariadic());
1648 }
1649 
1650 // Parses an LLVM function.
1651 //
1652 // operation ::= `llvm.func` linkage? function-signature function-attributes?
1653 //               function-body
1654 //
1655 static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
1656                                    OperationState &result) {
1657   // Default to external linkage if no keyword is provided.
1658   if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result,
1659                                                getLinkageAttrName())))
1660     result.addAttribute(getLinkageAttrName(),
1661                         parser.getBuilder().getI64IntegerAttr(
1662                             static_cast<int64_t>(LLVM::Linkage::External)));
1663 
1664   StringAttr nameAttr;
1665   SmallVector<OpAsmParser::OperandType, 8> entryArgs;
1666   SmallVector<NamedAttrList, 1> argAttrs;
1667   SmallVector<NamedAttrList, 1> resultAttrs;
1668   SmallVector<Type, 8> argTypes;
1669   SmallVector<Type, 4> resultTypes;
1670   bool isVariadic;
1671 
1672   auto signatureLocation = parser.getCurrentLocation();
1673   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1674                              result.attributes) ||
1675       impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs,
1676                                    argTypes, argAttrs, isVariadic, resultTypes,
1677                                    resultAttrs))
1678     return failure();
1679 
1680   auto type =
1681       buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
1682                             impl::VariadicFlag(isVariadic));
1683   if (!type)
1684     return failure();
1685   result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type));
1686 
1687   if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
1688     return failure();
1689   impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs,
1690                              resultAttrs);
1691 
1692   auto *body = result.addRegion();
1693   OptionalParseResult parseResult = parser.parseOptionalRegion(
1694       *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
1695   return failure(parseResult.hasValue() && failed(*parseResult));
1696 }
1697 
1698 // Print the LLVMFuncOp. Collects argument and result types and passes them to
1699 // helper functions. Drops "void" result since it cannot be parsed back. Skips
1700 // the external linkage since it is the default value.
1701 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
1702   p << op.getOperationName() << ' ';
1703   if (op.linkage() != LLVM::Linkage::External)
1704     p << stringifyLinkage(op.linkage()) << ' ';
1705   p.printSymbolName(op.getName());
1706 
1707   LLVMFunctionType fnType = op.getType();
1708   SmallVector<Type, 8> argTypes;
1709   SmallVector<Type, 1> resTypes;
1710   argTypes.reserve(fnType.getNumParams());
1711   for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i)
1712     argTypes.push_back(fnType.getParamType(i));
1713 
1714   Type returnType = fnType.getReturnType();
1715   if (!returnType.isa<LLVMVoidType>())
1716     resTypes.push_back(returnType);
1717 
1718   impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes);
1719   impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(),
1720                                 {getLinkageAttrName()});
1721 
1722   // Print the body if this is not an external function.
1723   Region &body = op.body();
1724   if (!body.empty())
1725     p.printRegion(body, /*printEntryBlockArgs=*/false,
1726                   /*printBlockTerminators=*/true);
1727 }
1728 
1729 // Hook for OpTrait::FunctionLike, called after verifying that the 'type'
1730 // attribute is present.  This can check for preconditions of the
1731 // getNumArguments hook not failing.
1732 LogicalResult LLVMFuncOp::verifyType() {
1733   auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMFunctionType>();
1734   if (!llvmType)
1735     return emitOpError("requires '" + getTypeAttrName() +
1736                        "' attribute of wrapped LLVM function type");
1737 
1738   return success();
1739 }
1740 
1741 // Hook for OpTrait::FunctionLike, returns the number of function arguments.
1742 // Depends on the type attribute being correct as checked by verifyType
1743 unsigned LLVMFuncOp::getNumFuncArguments() { return getType().getNumParams(); }
1744 
1745 // Hook for OpTrait::FunctionLike, returns the number of function results.
1746 // Depends on the type attribute being correct as checked by verifyType
1747 unsigned LLVMFuncOp::getNumFuncResults() {
1748   // We model LLVM functions that return void as having zero results,
1749   // and all others as having one result.
1750   // If we modeled a void return as one result, then it would be possible to
1751   // attach an MLIR result attribute to it, and it isn't clear what semantics we
1752   // would assign to that.
1753   if (getType().getReturnType().isa<LLVMVoidType>())
1754     return 0;
1755   return 1;
1756 }
1757 
1758 // Verifies LLVM- and implementation-specific properties of the LLVM func Op:
1759 // - functions don't have 'common' linkage
1760 // - external functions have 'external' or 'extern_weak' linkage;
1761 // - vararg is (currently) only supported for external functions;
1762 // - entry block arguments are of LLVM types and match the function signature.
1763 static LogicalResult verify(LLVMFuncOp op) {
1764   if (op.linkage() == LLVM::Linkage::Common)
1765     return op.emitOpError()
1766            << "functions cannot have '"
1767            << stringifyLinkage(LLVM::Linkage::Common) << "' linkage";
1768 
1769   if (op.isExternal()) {
1770     if (op.linkage() != LLVM::Linkage::External &&
1771         op.linkage() != LLVM::Linkage::ExternWeak)
1772       return op.emitOpError()
1773              << "external functions must have '"
1774              << stringifyLinkage(LLVM::Linkage::External) << "' or '"
1775              << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage";
1776     return success();
1777   }
1778 
1779   if (op.isVarArg())
1780     return op.emitOpError("only external functions can be variadic");
1781 
1782   unsigned numArguments = op.getType().getNumParams();
1783   Block &entryBlock = op.front();
1784   for (unsigned i = 0; i < numArguments; ++i) {
1785     Type argType = entryBlock.getArgument(i).getType();
1786     if (!isCompatibleType(argType))
1787       return op.emitOpError("entry block argument #")
1788              << i << " is not of LLVM type";
1789     if (op.getType().getParamType(i) != argType)
1790       return op.emitOpError("the type of entry block argument #")
1791              << i << " does not match the function signature";
1792   }
1793 
1794   return success();
1795 }
1796 
1797 //===----------------------------------------------------------------------===//
1798 // Verification for LLVM::ConstantOp.
1799 //===----------------------------------------------------------------------===//
1800 
1801 static LogicalResult verify(LLVM::ConstantOp op) {
1802   if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() ||
1803         op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>()))
1804     return op.emitOpError()
1805            << "only supports integer, float, string or elements attributes";
1806   return success();
1807 }
1808 
1809 //===----------------------------------------------------------------------===//
1810 // Utility functions for parsing atomic ops
1811 //===----------------------------------------------------------------------===//
1812 
1813 // Helper function to parse a keyword into the specified attribute named by
1814 // `attrName`. The keyword must match one of the string values defined by the
1815 // AtomicBinOp enum. The resulting I64 attribute is added to the `result`
1816 // state.
1817 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result,
1818                                     StringRef attrName) {
1819   llvm::SMLoc loc;
1820   StringRef keyword;
1821   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword))
1822     return failure();
1823 
1824   // Replace the keyword `keyword` with an integer attribute.
1825   auto kind = symbolizeAtomicBinOp(keyword);
1826   if (!kind) {
1827     return parser.emitError(loc)
1828            << "'" << keyword << "' is an incorrect value of the '" << attrName
1829            << "' attribute";
1830   }
1831 
1832   auto value = static_cast<int64_t>(kind.getValue());
1833   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1834   result.addAttribute(attrName, attr);
1835 
1836   return success();
1837 }
1838 
1839 // Helper function to parse a keyword into the specified attribute named by
1840 // `attrName`. The keyword must match one of the string values defined by the
1841 // AtomicOrdering enum. The resulting I64 attribute is added to the `result`
1842 // state.
1843 static ParseResult parseAtomicOrdering(OpAsmParser &parser,
1844                                        OperationState &result,
1845                                        StringRef attrName) {
1846   llvm::SMLoc loc;
1847   StringRef ordering;
1848   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering))
1849     return failure();
1850 
1851   // Replace the keyword `ordering` with an integer attribute.
1852   auto kind = symbolizeAtomicOrdering(ordering);
1853   if (!kind) {
1854     return parser.emitError(loc)
1855            << "'" << ordering << "' is an incorrect value of the '" << attrName
1856            << "' attribute";
1857   }
1858 
1859   auto value = static_cast<int64_t>(kind.getValue());
1860   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1861   result.addAttribute(attrName, attr);
1862 
1863   return success();
1864 }
1865 
1866 //===----------------------------------------------------------------------===//
1867 // Printer, parser and verifier for LLVM::AtomicRMWOp.
1868 //===----------------------------------------------------------------------===//
1869 
1870 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) {
1871   p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' '
1872     << op.ptr() << ", " << op.val() << ' '
1873     << stringifyAtomicOrdering(op.ordering()) << ' ';
1874   p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"});
1875   p << " : " << op.res().getType();
1876 }
1877 
1878 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword
1879 //                 attribute-dict? `:` type
1880 static ParseResult parseAtomicRMWOp(OpAsmParser &parser,
1881                                     OperationState &result) {
1882   Type type;
1883   OpAsmParser::OperandType ptr, val;
1884   if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) ||
1885       parser.parseComma() || parser.parseOperand(val) ||
1886       parseAtomicOrdering(parser, result, "ordering") ||
1887       parser.parseOptionalAttrDict(result.attributes) ||
1888       parser.parseColonType(type) ||
1889       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
1890                             result.operands) ||
1891       parser.resolveOperand(val, type, result.operands))
1892     return failure();
1893 
1894   result.addTypes(type);
1895   return success();
1896 }
1897 
1898 static LogicalResult verify(AtomicRMWOp op) {
1899   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
1900   auto valType = op.val().getType();
1901   if (valType != ptrType.getElementType())
1902     return op.emitOpError("expected LLVM IR element type for operand #0 to "
1903                           "match type for operand #1");
1904   auto resType = op.res().getType();
1905   if (resType != valType)
1906     return op.emitOpError(
1907         "expected LLVM IR result type to match type for operand #1");
1908   if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) {
1909     if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
1910       return op.emitOpError("expected LLVM IR floating point type");
1911   } else if (op.bin_op() == AtomicBinOp::xchg) {
1912     auto intType = valType.dyn_cast<IntegerType>();
1913     unsigned intBitWidth = intType ? intType.getWidth() : 0;
1914     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
1915         intBitWidth != 64 && !valType.isa<BFloat16Type>() &&
1916         !valType.isa<Float16Type>() && !valType.isa<Float32Type>() &&
1917         !valType.isa<Float64Type>())
1918       return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
1919   } else {
1920     auto intType = valType.dyn_cast<IntegerType>();
1921     unsigned intBitWidth = intType ? intType.getWidth() : 0;
1922     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
1923         intBitWidth != 64)
1924       return op.emitOpError("expected LLVM IR integer type");
1925   }
1926   return success();
1927 }
1928 
1929 //===----------------------------------------------------------------------===//
1930 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp.
1931 //===----------------------------------------------------------------------===//
1932 
1933 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) {
1934   p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", "
1935     << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' '
1936     << stringifyAtomicOrdering(op.failure_ordering());
1937   p.printOptionalAttrDict(op.getAttrs(),
1938                           {"success_ordering", "failure_ordering"});
1939   p << " : " << op.val().getType();
1940 }
1941 
1942 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use
1943 //                 keyword keyword attribute-dict? `:` type
1944 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser,
1945                                         OperationState &result) {
1946   auto &builder = parser.getBuilder();
1947   Type type;
1948   OpAsmParser::OperandType ptr, cmp, val;
1949   if (parser.parseOperand(ptr) || parser.parseComma() ||
1950       parser.parseOperand(cmp) || parser.parseComma() ||
1951       parser.parseOperand(val) ||
1952       parseAtomicOrdering(parser, result, "success_ordering") ||
1953       parseAtomicOrdering(parser, result, "failure_ordering") ||
1954       parser.parseOptionalAttrDict(result.attributes) ||
1955       parser.parseColonType(type) ||
1956       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
1957                             result.operands) ||
1958       parser.resolveOperand(cmp, type, result.operands) ||
1959       parser.resolveOperand(val, type, result.operands))
1960     return failure();
1961 
1962   auto boolType = IntegerType::get(builder.getContext(), 1);
1963   auto resultType =
1964       LLVMStructType::getLiteral(builder.getContext(), {type, boolType});
1965   result.addTypes(resultType);
1966 
1967   return success();
1968 }
1969 
1970 static LogicalResult verify(AtomicCmpXchgOp op) {
1971   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
1972   if (!ptrType)
1973     return op.emitOpError("expected LLVM IR pointer type for operand #0");
1974   auto cmpType = op.cmp().getType();
1975   auto valType = op.val().getType();
1976   if (cmpType != ptrType.getElementType() || cmpType != valType)
1977     return op.emitOpError("expected LLVM IR element type for operand #0 to "
1978                           "match type for all other operands");
1979   auto intType = valType.dyn_cast<IntegerType>();
1980   unsigned intBitWidth = intType ? intType.getWidth() : 0;
1981   if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 &&
1982       intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 &&
1983       !valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() &&
1984       !valType.isa<Float32Type>() && !valType.isa<Float64Type>())
1985     return op.emitOpError("unexpected LLVM IR type");
1986   if (op.success_ordering() < AtomicOrdering::monotonic ||
1987       op.failure_ordering() < AtomicOrdering::monotonic)
1988     return op.emitOpError("ordering must be at least 'monotonic'");
1989   if (op.failure_ordering() == AtomicOrdering::release ||
1990       op.failure_ordering() == AtomicOrdering::acq_rel)
1991     return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
1992   return success();
1993 }
1994 
1995 //===----------------------------------------------------------------------===//
1996 // Printer, parser and verifier for LLVM::FenceOp.
1997 //===----------------------------------------------------------------------===//
1998 
1999 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword
2000 // attribute-dict?
2001 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) {
2002   StringAttr sScope;
2003   StringRef syncscopeKeyword = "syncscope";
2004   if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) {
2005     if (parser.parseLParen() ||
2006         parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) ||
2007         parser.parseRParen())
2008       return failure();
2009   } else {
2010     result.addAttribute(syncscopeKeyword,
2011                         parser.getBuilder().getStringAttr(""));
2012   }
2013   if (parseAtomicOrdering(parser, result, "ordering") ||
2014       parser.parseOptionalAttrDict(result.attributes))
2015     return failure();
2016   return success();
2017 }
2018 
2019 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) {
2020   StringRef syncscopeKeyword = "syncscope";
2021   p << op.getOperationName() << ' ';
2022   if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty())
2023     p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") ";
2024   p << stringifyAtomicOrdering(op.ordering());
2025 }
2026 
2027 static LogicalResult verify(FenceOp &op) {
2028   if (op.ordering() == AtomicOrdering::not_atomic ||
2029       op.ordering() == AtomicOrdering::unordered ||
2030       op.ordering() == AtomicOrdering::monotonic)
2031     return op.emitOpError("can be given only acquire, release, acq_rel, "
2032                           "and seq_cst orderings");
2033   return success();
2034 }
2035 
2036 //===----------------------------------------------------------------------===//
2037 // LLVMDialect initialization, type parsing, and registration.
2038 //===----------------------------------------------------------------------===//
2039 
2040 void LLVMDialect::initialize() {
2041   addAttributes<FMFAttr>();
2042 
2043   // clang-format off
2044   addTypes<LLVMVoidType,
2045            LLVMPPCFP128Type,
2046            LLVMX86MMXType,
2047            LLVMTokenType,
2048            LLVMLabelType,
2049            LLVMMetadataType,
2050            LLVMFunctionType,
2051            LLVMPointerType,
2052            LLVMFixedVectorType,
2053            LLVMScalableVectorType,
2054            LLVMArrayType,
2055            LLVMStructType>();
2056   // clang-format on
2057   addOperations<
2058 #define GET_OP_LIST
2059 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2060       >();
2061 
2062   // Support unknown operations because not all LLVM operations are registered.
2063   allowUnknownOperations();
2064 }
2065 
2066 #define GET_OP_CLASSES
2067 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2068 
2069 /// Parse a type registered to this dialect.
2070 Type LLVMDialect::parseType(DialectAsmParser &parser) const {
2071   return detail::parseType(parser);
2072 }
2073 
2074 /// Print a type registered to this dialect.
2075 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
2076   return detail::printType(type, os);
2077 }
2078 
2079 LogicalResult LLVMDialect::verifyDataLayoutString(
2080     StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
2081   llvm::Expected<llvm::DataLayout> maybeDataLayout =
2082       llvm::DataLayout::parse(descr);
2083   if (maybeDataLayout)
2084     return success();
2085 
2086   std::string message;
2087   llvm::raw_string_ostream messageStream(message);
2088   llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
2089   reportError("invalid data layout descriptor: " + messageStream.str());
2090   return failure();
2091 }
2092 
2093 /// Verify LLVM dialect attributes.
2094 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
2095                                                     NamedAttribute attr) {
2096   // If the data layout attribute is present, it must use the LLVM data layout
2097   // syntax. Try parsing it and report errors in case of failure. Users of this
2098   // attribute may assume it is well-formed and can pass it to the (asserting)
2099   // llvm::DataLayout constructor.
2100   if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName())
2101     return success();
2102   if (auto stringAttr = attr.second.dyn_cast<StringAttr>())
2103     return verifyDataLayoutString(
2104         stringAttr.getValue(),
2105         [op](const Twine &message) { op->emitOpError() << message.str(); });
2106 
2107   return op->emitOpError() << "expected '"
2108                            << LLVM::LLVMDialect::getDataLayoutAttrName()
2109                            << "' to be a string attribute";
2110 }
2111 
2112 /// Verify LLVMIR function argument attributes.
2113 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
2114                                                     unsigned regionIdx,
2115                                                     unsigned argIdx,
2116                                                     NamedAttribute argAttr) {
2117   // Check that llvm.noalias is a boolean attribute.
2118   if (argAttr.first == LLVMDialect::getNoAliasAttrName() &&
2119       !argAttr.second.isa<BoolAttr>())
2120     return op->emitError()
2121            << "llvm.noalias argument attribute of non boolean type";
2122   // Check that llvm.align is an integer attribute.
2123   if (argAttr.first == LLVMDialect::getAlignAttrName() &&
2124       !argAttr.second.isa<IntegerAttr>())
2125     return op->emitError()
2126            << "llvm.align argument attribute of non integer type";
2127   return success();
2128 }
2129 
2130 //===----------------------------------------------------------------------===//
2131 // Utility functions.
2132 //===----------------------------------------------------------------------===//
2133 
2134 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
2135                                      StringRef name, StringRef value,
2136                                      LLVM::Linkage linkage) {
2137   assert(builder.getInsertionBlock() &&
2138          builder.getInsertionBlock()->getParentOp() &&
2139          "expected builder to point to a block constrained in an op");
2140   auto module =
2141       builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
2142   assert(module && "builder points to an op outside of a module");
2143 
2144   // Create the global at the entry of the module.
2145   OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener());
2146   MLIRContext *ctx = builder.getContext();
2147   auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size());
2148   auto global = moduleBuilder.create<LLVM::GlobalOp>(
2149       loc, type, /*isConstant=*/true, linkage, name,
2150       builder.getStringAttr(value));
2151 
2152   // Get the pointer to the first character in the global string.
2153   Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
2154   Value cst0 = builder.create<LLVM::ConstantOp>(
2155       loc, IntegerType::get(ctx, 64),
2156       builder.getIntegerAttr(builder.getIndexType(), 0));
2157   return builder.create<LLVM::GEPOp>(
2158       loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr,
2159       ValueRange{cst0, cst0});
2160 }
2161 
2162 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
2163   return op->hasTrait<OpTrait::SymbolTable>() &&
2164          op->hasTrait<OpTrait::IsIsolatedFromAbove>();
2165 }
2166 
2167 FMFAttr FMFAttr::get(FastmathFlags flags, MLIRContext *context) {
2168   return Base::get(context, static_cast<uint64_t>(flags));
2169 }
2170 
2171 FastmathFlags FMFAttr::getFlags() const {
2172   return static_cast<FastmathFlags>(getImpl()->value);
2173 }
2174 
2175 static constexpr const FastmathFlags FastmathFlagsList[] = {
2176     // clang-format off
2177     FastmathFlags::nnan,
2178     FastmathFlags::ninf,
2179     FastmathFlags::nsz,
2180     FastmathFlags::arcp,
2181     FastmathFlags::contract,
2182     FastmathFlags::afn,
2183     FastmathFlags::reassoc,
2184     FastmathFlags::fast,
2185     // clang-format on
2186 };
2187 
2188 void FMFAttr::print(DialectAsmPrinter &printer) const {
2189   printer << "fastmath<";
2190   auto flags = llvm::make_filter_range(FastmathFlagsList, [&](auto flag) {
2191     return bitEnumContains(this->getFlags(), flag);
2192   });
2193   llvm::interleaveComma(flags, printer,
2194                         [&](auto flag) { printer << stringifyEnum(flag); });
2195   printer << ">";
2196 }
2197 
2198 Attribute FMFAttr::parse(DialectAsmParser &parser) {
2199   if (failed(parser.parseLess()))
2200     return {};
2201 
2202   FastmathFlags flags = {};
2203   if (failed(parser.parseOptionalGreater())) {
2204     do {
2205       StringRef elemName;
2206       if (failed(parser.parseKeyword(&elemName)))
2207         return {};
2208 
2209       auto elem = symbolizeFastmathFlags(elemName);
2210       if (!elem) {
2211         parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ")
2212             << elemName;
2213         return {};
2214       }
2215 
2216       flags = flags | *elem;
2217     } while (succeeded(parser.parseOptionalComma()));
2218 
2219     if (failed(parser.parseGreater()))
2220       return {};
2221   }
2222 
2223   return FMFAttr::get(flags, parser.getBuilder().getContext());
2224 }
2225 
2226 Attribute LLVMDialect::parseAttribute(DialectAsmParser &parser,
2227                                       Type type) const {
2228   if (type) {
2229     parser.emitError(parser.getNameLoc(), "unexpected type");
2230     return {};
2231   }
2232   StringRef attrKind;
2233   if (parser.parseKeyword(&attrKind))
2234     return {};
2235 
2236   if (attrKind == "fastmath")
2237     return FMFAttr::parse(parser);
2238 
2239   parser.emitError(parser.getNameLoc(), "Unknown attrribute type: ")
2240       << attrKind;
2241   return {};
2242 }
2243 
2244 void LLVMDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
2245   if (auto fmf = attr.dyn_cast<FMFAttr>())
2246     fmf.print(os);
2247   else
2248     llvm_unreachable("Unknown attribute type");
2249 }
2250