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