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 (op.unnamed_addr())
1414     p << stringifyUnnamedAddr(*op.unnamed_addr()) << ' ';
1415   if (op.constant())
1416     p << "constant ";
1417   p.printSymbolName(op.sym_name());
1418   p << '(';
1419   if (auto value = op.getValueOrNull())
1420     p.printAttribute(value);
1421   p << ')';
1422   // Note that the alignment attribute is printed using the
1423   // default syntax here, even though it is an inherent attribute
1424   // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes)
1425   p.printOptionalAttrDict(op->getAttrs(),
1426                           {SymbolTable::getSymbolAttrName(), "type", "constant",
1427                            "value", getLinkageAttrName(),
1428                            getUnnamedAddrAttrName()});
1429 
1430   // Print the trailing type unless it's a string global.
1431   if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
1432     return;
1433   p << " : " << op.type();
1434 
1435   Region &initializer = op.getInitializerRegion();
1436   if (!initializer.empty())
1437     p.printRegion(initializer, /*printEntryBlockArgs=*/false);
1438 }
1439 
1440 // Parses one of the keywords provided in the list `keywords` and returns the
1441 // position of the parsed keyword in the list. If none of the keywords from the
1442 // list is parsed, returns -1.
1443 static int parseOptionalKeywordAlternative(OpAsmParser &parser,
1444                                            ArrayRef<StringRef> keywords) {
1445   for (auto en : llvm::enumerate(keywords)) {
1446     if (succeeded(parser.parseOptionalKeyword(en.value())))
1447       return en.index();
1448   }
1449   return -1;
1450 }
1451 
1452 namespace {
1453 template <typename Ty>
1454 struct EnumTraits {};
1455 
1456 #define REGISTER_ENUM_TYPE(Ty)                                                 \
1457   template <>                                                                  \
1458   struct EnumTraits<Ty> {                                                      \
1459     static StringRef stringify(Ty value) { return stringify##Ty(value); }      \
1460     static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); }         \
1461   }
1462 
1463 REGISTER_ENUM_TYPE(Linkage);
1464 REGISTER_ENUM_TYPE(UnnamedAddr);
1465 } // end namespace
1466 
1467 /// Parse an enum from the keyword, or default to the provided default value.
1468 /// The return type is the enum type by default, unless overriden with the
1469 /// second template argument.
1470 template <typename EnumTy, typename RetTy = EnumTy>
1471 static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser,
1472                                       OperationState &result,
1473                                       EnumTy defaultValue) {
1474   SmallVector<StringRef, 10> names;
1475   for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i)
1476     names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));
1477 
1478   int index = parseOptionalKeywordAlternative(parser, names);
1479   if (index == -1)
1480     return static_cast<RetTy>(defaultValue);
1481   return static_cast<RetTy>(index);
1482 }
1483 
1484 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
1485 //               `(` attribute? `)` align? attribute-list? (`:` type)? region?
1486 // align     ::= `align` `=` UINT64
1487 //
1488 // The type can be omitted for string attributes, in which case it will be
1489 // inferred from the value of the string as [strlen(value) x i8].
1490 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
1491   MLIRContext *ctx = parser.getBuilder().getContext();
1492   // Parse optional linkage, default to External.
1493   result.addAttribute(getLinkageAttrName(),
1494                       LLVM::LinkageAttr::get(
1495                           ctx, parseOptionalLLVMKeyword<Linkage>(
1496                                    parser, result, LLVM::Linkage::External)));
1497   // Parse optional UnnamedAddr, default to None.
1498   result.addAttribute(getUnnamedAddrAttrName(),
1499                       parser.getBuilder().getI64IntegerAttr(
1500                           parseOptionalLLVMKeyword<UnnamedAddr, int64_t>(
1501                               parser, result, LLVM::UnnamedAddr::None)));
1502 
1503   if (succeeded(parser.parseOptionalKeyword("constant")))
1504     result.addAttribute("constant", parser.getBuilder().getUnitAttr());
1505 
1506   StringAttr name;
1507   if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(),
1508                              result.attributes) ||
1509       parser.parseLParen())
1510     return failure();
1511 
1512   Attribute value;
1513   if (parser.parseOptionalRParen()) {
1514     if (parser.parseAttribute(value, "value", result.attributes) ||
1515         parser.parseRParen())
1516       return failure();
1517   }
1518 
1519   SmallVector<Type, 1> types;
1520   if (parser.parseOptionalAttrDict(result.attributes) ||
1521       parser.parseOptionalColonTypeList(types))
1522     return failure();
1523 
1524   if (types.size() > 1)
1525     return parser.emitError(parser.getNameLoc(), "expected zero or one type");
1526 
1527   Region &initRegion = *result.addRegion();
1528   if (types.empty()) {
1529     if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) {
1530       MLIRContext *context = parser.getBuilder().getContext();
1531       auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8),
1532                                                 strAttr.getValue().size());
1533       types.push_back(arrayType);
1534     } else {
1535       return parser.emitError(parser.getNameLoc(),
1536                               "type can only be omitted for string globals");
1537     }
1538   } else {
1539     OptionalParseResult parseResult =
1540         parser.parseOptionalRegion(initRegion, /*arguments=*/{},
1541                                    /*argTypes=*/{});
1542     if (parseResult.hasValue() && failed(*parseResult))
1543       return failure();
1544   }
1545 
1546   result.addAttribute("type", TypeAttr::get(types[0]));
1547   return success();
1548 }
1549 
1550 static bool isZeroAttribute(Attribute value) {
1551   if (auto intValue = value.dyn_cast<IntegerAttr>())
1552     return intValue.getValue().isNullValue();
1553   if (auto fpValue = value.dyn_cast<FloatAttr>())
1554     return fpValue.getValue().isZero();
1555   if (auto splatValue = value.dyn_cast<SplatElementsAttr>())
1556     return isZeroAttribute(splatValue.getSplatValue());
1557   if (auto elementsValue = value.dyn_cast<ElementsAttr>())
1558     return llvm::all_of(elementsValue.getValues<Attribute>(), isZeroAttribute);
1559   if (auto arrayValue = value.dyn_cast<ArrayAttr>())
1560     return llvm::all_of(arrayValue.getValue(), isZeroAttribute);
1561   return false;
1562 }
1563 
1564 static LogicalResult verify(GlobalOp op) {
1565   if (!LLVMPointerType::isValidElementType(op.getType()))
1566     return op.emitOpError(
1567         "expects type to be a valid element type for an LLVM pointer");
1568   if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp()))
1569     return op.emitOpError("must appear at the module level");
1570 
1571   if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) {
1572     auto type = op.getType().dyn_cast<LLVMArrayType>();
1573     IntegerType elementType =
1574         type ? type.getElementType().dyn_cast<IntegerType>() : nullptr;
1575     if (!elementType || elementType.getWidth() != 8 ||
1576         type.getNumElements() != strAttr.getValue().size())
1577       return op.emitOpError(
1578           "requires an i8 array type of the length equal to that of the string "
1579           "attribute");
1580   }
1581 
1582   if (Block *b = op.getInitializerBlock()) {
1583     ReturnOp ret = cast<ReturnOp>(b->getTerminator());
1584     if (ret.operand_type_begin() == ret.operand_type_end())
1585       return op.emitOpError("initializer region cannot return void");
1586     if (*ret.operand_type_begin() != op.getType())
1587       return op.emitOpError("initializer region type ")
1588              << *ret.operand_type_begin() << " does not match global type "
1589              << op.getType();
1590 
1591     if (op.getValueOrNull())
1592       return op.emitOpError("cannot have both initializer value and region");
1593   }
1594 
1595   if (op.linkage() == Linkage::Common) {
1596     if (Attribute value = op.getValueOrNull()) {
1597       if (!isZeroAttribute(value)) {
1598         return op.emitOpError()
1599                << "expected zero value for '"
1600                << stringifyLinkage(Linkage::Common) << "' linkage";
1601       }
1602     }
1603   }
1604 
1605   if (op.linkage() == Linkage::Appending) {
1606     if (!op.getType().isa<LLVMArrayType>()) {
1607       return op.emitOpError()
1608              << "expected array type for '"
1609              << stringifyLinkage(Linkage::Appending) << "' linkage";
1610     }
1611   }
1612 
1613   Optional<uint64_t> alignAttr = op.alignment();
1614   if (alignAttr.hasValue()) {
1615     uint64_t value = alignAttr.getValue();
1616     if (!llvm::isPowerOf2_64(value))
1617       return op->emitError() << "alignment attribute is not a power of 2";
1618   }
1619 
1620   return success();
1621 }
1622 
1623 //===----------------------------------------------------------------------===//
1624 // Printing/parsing for LLVM::ShuffleVectorOp.
1625 //===----------------------------------------------------------------------===//
1626 // Expects vector to be of wrapped LLVM vector type and position to be of
1627 // wrapped LLVM i32 type.
1628 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result,
1629                                   Value v1, Value v2, ArrayAttr mask,
1630                                   ArrayRef<NamedAttribute> attrs) {
1631   auto containerType = v1.getType();
1632   auto vType = LLVM::getFixedVectorType(
1633       LLVM::getVectorElementType(containerType), mask.size());
1634   build(b, result, vType, v1, v2, mask);
1635   result.addAttributes(attrs);
1636 }
1637 
1638 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) {
1639   p << ' ' << op.v1() << ", " << op.v2() << " " << op.mask();
1640   p.printOptionalAttrDict(op->getAttrs(), {"mask"});
1641   p << " : " << op.v1().getType() << ", " << op.v2().getType();
1642 }
1643 
1644 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use
1645 //                 `[` integer-literal (`,` integer-literal)* `]`
1646 //                 attribute-dict? `:` type
1647 static ParseResult parseShuffleVectorOp(OpAsmParser &parser,
1648                                         OperationState &result) {
1649   llvm::SMLoc loc;
1650   OpAsmParser::OperandType v1, v2;
1651   ArrayAttr maskAttr;
1652   Type typeV1, typeV2;
1653   if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) ||
1654       parser.parseComma() || parser.parseOperand(v2) ||
1655       parser.parseAttribute(maskAttr, "mask", result.attributes) ||
1656       parser.parseOptionalAttrDict(result.attributes) ||
1657       parser.parseColonType(typeV1) || parser.parseComma() ||
1658       parser.parseType(typeV2) ||
1659       parser.resolveOperand(v1, typeV1, result.operands) ||
1660       parser.resolveOperand(v2, typeV2, result.operands))
1661     return failure();
1662   if (!LLVM::isCompatibleVectorType(typeV1))
1663     return parser.emitError(
1664         loc, "expected LLVM IR dialect vector type for operand #1");
1665   auto vType = LLVM::getFixedVectorType(LLVM::getVectorElementType(typeV1),
1666                                         maskAttr.size());
1667   result.addTypes(vType);
1668   return success();
1669 }
1670 
1671 //===----------------------------------------------------------------------===//
1672 // Implementations for LLVM::LLVMFuncOp.
1673 //===----------------------------------------------------------------------===//
1674 
1675 // Add the entry block to the function.
1676 Block *LLVMFuncOp::addEntryBlock() {
1677   assert(empty() && "function already has an entry block");
1678   assert(!isVarArg() && "unimplemented: non-external variadic functions");
1679 
1680   auto *entry = new Block;
1681   push_back(entry);
1682 
1683   LLVMFunctionType type = getType();
1684   for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
1685     entry->addArgument(type.getParamType(i));
1686   return entry;
1687 }
1688 
1689 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result,
1690                        StringRef name, Type type, LLVM::Linkage linkage,
1691                        bool dsoLocal, ArrayRef<NamedAttribute> attrs,
1692                        ArrayRef<DictionaryAttr> argAttrs) {
1693   result.addRegion();
1694   result.addAttribute(SymbolTable::getSymbolAttrName(),
1695                       builder.getStringAttr(name));
1696   result.addAttribute("type", TypeAttr::get(type));
1697   result.addAttribute(getLinkageAttrName(),
1698                       LinkageAttr::get(builder.getContext(), linkage));
1699   result.attributes.append(attrs.begin(), attrs.end());
1700   if (dsoLocal)
1701     result.addAttribute("dso_local", builder.getUnitAttr());
1702   if (argAttrs.empty())
1703     return;
1704 
1705   assert(type.cast<LLVMFunctionType>().getNumParams() == argAttrs.size() &&
1706          "expected as many argument attribute lists as arguments");
1707   function_like_impl::addArgAndResultAttrs(builder, result, argAttrs,
1708                                            /*resultAttrs=*/llvm::None);
1709 }
1710 
1711 // Builds an LLVM function type from the given lists of input and output types.
1712 // Returns a null type if any of the types provided are non-LLVM types, or if
1713 // there is more than one output type.
1714 static Type
1715 buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
1716                       ArrayRef<Type> inputs, ArrayRef<Type> outputs,
1717                       function_like_impl::VariadicFlag variadicFlag) {
1718   Builder &b = parser.getBuilder();
1719   if (outputs.size() > 1) {
1720     parser.emitError(loc, "failed to construct function type: expected zero or "
1721                           "one function result");
1722     return {};
1723   }
1724 
1725   // Convert inputs to LLVM types, exit early on error.
1726   SmallVector<Type, 4> llvmInputs;
1727   for (auto t : inputs) {
1728     if (!isCompatibleType(t)) {
1729       parser.emitError(loc, "failed to construct function type: expected LLVM "
1730                             "type for function arguments");
1731       return {};
1732     }
1733     llvmInputs.push_back(t);
1734   }
1735 
1736   // No output is denoted as "void" in LLVM type system.
1737   Type llvmOutput =
1738       outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front();
1739   if (!isCompatibleType(llvmOutput)) {
1740     parser.emitError(loc, "failed to construct function type: expected LLVM "
1741                           "type for function results")
1742         << llvmOutput;
1743     return {};
1744   }
1745   return LLVMFunctionType::get(llvmOutput, llvmInputs,
1746                                variadicFlag.isVariadic());
1747 }
1748 
1749 // Parses an LLVM function.
1750 //
1751 // operation ::= `llvm.func` linkage? function-signature function-attributes?
1752 //               function-body
1753 //
1754 static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
1755                                    OperationState &result) {
1756   // Default to external linkage if no keyword is provided.
1757   result.addAttribute(
1758       getLinkageAttrName(),
1759       LinkageAttr::get(parser.getBuilder().getContext(),
1760                        parseOptionalLLVMKeyword<Linkage>(
1761                            parser, result, LLVM::Linkage::External)));
1762 
1763   StringAttr nameAttr;
1764   SmallVector<OpAsmParser::OperandType, 8> entryArgs;
1765   SmallVector<NamedAttrList, 1> argAttrs;
1766   SmallVector<NamedAttrList, 1> resultAttrs;
1767   SmallVector<Type, 8> argTypes;
1768   SmallVector<Type, 4> resultTypes;
1769   bool isVariadic;
1770 
1771   auto signatureLocation = parser.getCurrentLocation();
1772   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1773                              result.attributes) ||
1774       function_like_impl::parseFunctionSignature(
1775           parser, /*allowVariadic=*/true, entryArgs, argTypes, argAttrs,
1776           isVariadic, resultTypes, resultAttrs))
1777     return failure();
1778 
1779   auto type =
1780       buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
1781                             function_like_impl::VariadicFlag(isVariadic));
1782   if (!type)
1783     return failure();
1784   result.addAttribute(function_like_impl::getTypeAttrName(),
1785                       TypeAttr::get(type));
1786 
1787   if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
1788     return failure();
1789   function_like_impl::addArgAndResultAttrs(parser.getBuilder(), result,
1790                                            argAttrs, resultAttrs);
1791 
1792   auto *body = result.addRegion();
1793   OptionalParseResult parseResult = parser.parseOptionalRegion(
1794       *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
1795   return failure(parseResult.hasValue() && failed(*parseResult));
1796 }
1797 
1798 // Print the LLVMFuncOp. Collects argument and result types and passes them to
1799 // helper functions. Drops "void" result since it cannot be parsed back. Skips
1800 // the external linkage since it is the default value.
1801 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
1802   p << ' ';
1803   if (op.linkage() != LLVM::Linkage::External)
1804     p << stringifyLinkage(op.linkage()) << ' ';
1805   p.printSymbolName(op.getName());
1806 
1807   LLVMFunctionType fnType = op.getType();
1808   SmallVector<Type, 8> argTypes;
1809   SmallVector<Type, 1> resTypes;
1810   argTypes.reserve(fnType.getNumParams());
1811   for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i)
1812     argTypes.push_back(fnType.getParamType(i));
1813 
1814   Type returnType = fnType.getReturnType();
1815   if (!returnType.isa<LLVMVoidType>())
1816     resTypes.push_back(returnType);
1817 
1818   function_like_impl::printFunctionSignature(p, op, argTypes, op.isVarArg(),
1819                                              resTypes);
1820   function_like_impl::printFunctionAttributes(
1821       p, op, argTypes.size(), resTypes.size(), {getLinkageAttrName()});
1822 
1823   // Print the body if this is not an external function.
1824   Region &body = op.body();
1825   if (!body.empty())
1826     p.printRegion(body, /*printEntryBlockArgs=*/false,
1827                   /*printBlockTerminators=*/true);
1828 }
1829 
1830 // Hook for OpTrait::FunctionLike, called after verifying that the 'type'
1831 // attribute is present.  This can check for preconditions of the
1832 // getNumArguments hook not failing.
1833 LogicalResult LLVMFuncOp::verifyType() {
1834   auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMFunctionType>();
1835   if (!llvmType)
1836     return emitOpError("requires '" + getTypeAttrName() +
1837                        "' attribute of wrapped LLVM function type");
1838 
1839   return success();
1840 }
1841 
1842 // Hook for OpTrait::FunctionLike, returns the number of function arguments.
1843 // Depends on the type attribute being correct as checked by verifyType
1844 unsigned LLVMFuncOp::getNumFuncArguments() { return getType().getNumParams(); }
1845 
1846 // Hook for OpTrait::FunctionLike, returns the number of function results.
1847 // Depends on the type attribute being correct as checked by verifyType
1848 unsigned LLVMFuncOp::getNumFuncResults() {
1849   // We model LLVM functions that return void as having zero results,
1850   // and all others as having one result.
1851   // If we modeled a void return as one result, then it would be possible to
1852   // attach an MLIR result attribute to it, and it isn't clear what semantics we
1853   // would assign to that.
1854   if (getType().getReturnType().isa<LLVMVoidType>())
1855     return 0;
1856   return 1;
1857 }
1858 
1859 // Verifies LLVM- and implementation-specific properties of the LLVM func Op:
1860 // - functions don't have 'common' linkage
1861 // - external functions have 'external' or 'extern_weak' linkage;
1862 // - vararg is (currently) only supported for external functions;
1863 // - entry block arguments are of LLVM types and match the function signature.
1864 static LogicalResult verify(LLVMFuncOp op) {
1865   if (op.linkage() == LLVM::Linkage::Common)
1866     return op.emitOpError()
1867            << "functions cannot have '"
1868            << stringifyLinkage(LLVM::Linkage::Common) << "' linkage";
1869 
1870   if (op.isExternal()) {
1871     if (op.linkage() != LLVM::Linkage::External &&
1872         op.linkage() != LLVM::Linkage::ExternWeak)
1873       return op.emitOpError()
1874              << "external functions must have '"
1875              << stringifyLinkage(LLVM::Linkage::External) << "' or '"
1876              << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage";
1877     return success();
1878   }
1879 
1880   if (op.isVarArg())
1881     return op.emitOpError("only external functions can be variadic");
1882 
1883   unsigned numArguments = op.getType().getNumParams();
1884   Block &entryBlock = op.front();
1885   for (unsigned i = 0; i < numArguments; ++i) {
1886     Type argType = entryBlock.getArgument(i).getType();
1887     if (!isCompatibleType(argType))
1888       return op.emitOpError("entry block argument #")
1889              << i << " is not of LLVM type";
1890     if (op.getType().getParamType(i) != argType)
1891       return op.emitOpError("the type of entry block argument #")
1892              << i << " does not match the function signature";
1893   }
1894 
1895   return success();
1896 }
1897 
1898 //===----------------------------------------------------------------------===//
1899 // Verification for LLVM::ConstantOp.
1900 //===----------------------------------------------------------------------===//
1901 
1902 static LogicalResult verify(LLVM::ConstantOp op) {
1903   if (StringAttr sAttr = op.value().dyn_cast<StringAttr>()) {
1904     auto arrayType = op.getType().dyn_cast<LLVMArrayType>();
1905     if (!arrayType || arrayType.getNumElements() != sAttr.getValue().size() ||
1906         !arrayType.getElementType().isInteger(8)) {
1907       return op->emitOpError()
1908              << "expected array type of " << sAttr.getValue().size()
1909              << " i8 elements for the string constant";
1910     }
1911     return success();
1912   }
1913   if (auto structType = op.getType().dyn_cast<LLVMStructType>()) {
1914     if (structType.getBody().size() != 2 ||
1915         structType.getBody()[0] != structType.getBody()[1]) {
1916       return op.emitError() << "expected struct type with two elements of the "
1917                                "same type, the type of a complex constant";
1918     }
1919 
1920     auto arrayAttr = op.value().dyn_cast<ArrayAttr>();
1921     if (!arrayAttr || arrayAttr.size() != 2 ||
1922         arrayAttr[0].getType() != arrayAttr[1].getType()) {
1923       return op.emitOpError() << "expected array attribute with two elements, "
1924                                  "representing a complex constant";
1925     }
1926 
1927     Type elementType = structType.getBody()[0];
1928     if (!elementType
1929              .isa<IntegerType, Float16Type, Float32Type, Float64Type>()) {
1930       return op.emitError()
1931              << "expected struct element types to be floating point type or "
1932                 "integer type";
1933     }
1934     return success();
1935   }
1936   if (!op.value().isa<IntegerAttr, ArrayAttr, FloatAttr, ElementsAttr>())
1937     return op.emitOpError()
1938            << "only supports integer, float, string or elements attributes";
1939   return success();
1940 }
1941 
1942 //===----------------------------------------------------------------------===//
1943 // Utility functions for parsing atomic ops
1944 //===----------------------------------------------------------------------===//
1945 
1946 // Helper function to parse a keyword into the specified attribute named by
1947 // `attrName`. The keyword must match one of the string values defined by the
1948 // AtomicBinOp enum. The resulting I64 attribute is added to the `result`
1949 // state.
1950 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result,
1951                                     StringRef attrName) {
1952   llvm::SMLoc loc;
1953   StringRef keyword;
1954   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword))
1955     return failure();
1956 
1957   // Replace the keyword `keyword` with an integer attribute.
1958   auto kind = symbolizeAtomicBinOp(keyword);
1959   if (!kind) {
1960     return parser.emitError(loc)
1961            << "'" << keyword << "' is an incorrect value of the '" << attrName
1962            << "' attribute";
1963   }
1964 
1965   auto value = static_cast<int64_t>(kind.getValue());
1966   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1967   result.addAttribute(attrName, attr);
1968 
1969   return success();
1970 }
1971 
1972 // Helper function to parse a keyword into the specified attribute named by
1973 // `attrName`. The keyword must match one of the string values defined by the
1974 // AtomicOrdering enum. The resulting I64 attribute is added to the `result`
1975 // state.
1976 static ParseResult parseAtomicOrdering(OpAsmParser &parser,
1977                                        OperationState &result,
1978                                        StringRef attrName) {
1979   llvm::SMLoc loc;
1980   StringRef ordering;
1981   if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering))
1982     return failure();
1983 
1984   // Replace the keyword `ordering` with an integer attribute.
1985   auto kind = symbolizeAtomicOrdering(ordering);
1986   if (!kind) {
1987     return parser.emitError(loc)
1988            << "'" << ordering << "' is an incorrect value of the '" << attrName
1989            << "' attribute";
1990   }
1991 
1992   auto value = static_cast<int64_t>(kind.getValue());
1993   auto attr = parser.getBuilder().getI64IntegerAttr(value);
1994   result.addAttribute(attrName, attr);
1995 
1996   return success();
1997 }
1998 
1999 //===----------------------------------------------------------------------===//
2000 // Printer, parser and verifier for LLVM::AtomicRMWOp.
2001 //===----------------------------------------------------------------------===//
2002 
2003 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) {
2004   p << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' << op.ptr() << ", "
2005     << op.val() << ' ' << stringifyAtomicOrdering(op.ordering()) << ' ';
2006   p.printOptionalAttrDict(op->getAttrs(), {"bin_op", "ordering"});
2007   p << " : " << op.res().getType();
2008 }
2009 
2010 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword
2011 //                 attribute-dict? `:` type
2012 static ParseResult parseAtomicRMWOp(OpAsmParser &parser,
2013                                     OperationState &result) {
2014   Type type;
2015   OpAsmParser::OperandType ptr, val;
2016   if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) ||
2017       parser.parseComma() || parser.parseOperand(val) ||
2018       parseAtomicOrdering(parser, result, "ordering") ||
2019       parser.parseOptionalAttrDict(result.attributes) ||
2020       parser.parseColonType(type) ||
2021       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
2022                             result.operands) ||
2023       parser.resolveOperand(val, type, result.operands))
2024     return failure();
2025 
2026   result.addTypes(type);
2027   return success();
2028 }
2029 
2030 static LogicalResult verify(AtomicRMWOp op) {
2031   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
2032   auto valType = op.val().getType();
2033   if (valType != ptrType.getElementType())
2034     return op.emitOpError("expected LLVM IR element type for operand #0 to "
2035                           "match type for operand #1");
2036   auto resType = op.res().getType();
2037   if (resType != valType)
2038     return op.emitOpError(
2039         "expected LLVM IR result type to match type for operand #1");
2040   if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) {
2041     if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
2042       return op.emitOpError("expected LLVM IR floating point type");
2043   } else if (op.bin_op() == AtomicBinOp::xchg) {
2044     auto intType = valType.dyn_cast<IntegerType>();
2045     unsigned intBitWidth = intType ? intType.getWidth() : 0;
2046     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
2047         intBitWidth != 64 && !valType.isa<BFloat16Type>() &&
2048         !valType.isa<Float16Type>() && !valType.isa<Float32Type>() &&
2049         !valType.isa<Float64Type>())
2050       return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
2051   } else {
2052     auto intType = valType.dyn_cast<IntegerType>();
2053     unsigned intBitWidth = intType ? intType.getWidth() : 0;
2054     if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
2055         intBitWidth != 64)
2056       return op.emitOpError("expected LLVM IR integer type");
2057   }
2058 
2059   if (static_cast<unsigned>(op.ordering()) <
2060       static_cast<unsigned>(AtomicOrdering::monotonic))
2061     return op.emitOpError()
2062            << "expected at least '"
2063            << stringifyAtomicOrdering(AtomicOrdering::monotonic)
2064            << "' ordering";
2065 
2066   return success();
2067 }
2068 
2069 //===----------------------------------------------------------------------===//
2070 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp.
2071 //===----------------------------------------------------------------------===//
2072 
2073 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) {
2074   p << ' ' << op.ptr() << ", " << op.cmp() << ", " << op.val() << ' '
2075     << stringifyAtomicOrdering(op.success_ordering()) << ' '
2076     << stringifyAtomicOrdering(op.failure_ordering());
2077   p.printOptionalAttrDict(op->getAttrs(),
2078                           {"success_ordering", "failure_ordering"});
2079   p << " : " << op.val().getType();
2080 }
2081 
2082 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use
2083 //                 keyword keyword attribute-dict? `:` type
2084 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser,
2085                                         OperationState &result) {
2086   auto &builder = parser.getBuilder();
2087   Type type;
2088   OpAsmParser::OperandType ptr, cmp, val;
2089   if (parser.parseOperand(ptr) || parser.parseComma() ||
2090       parser.parseOperand(cmp) || parser.parseComma() ||
2091       parser.parseOperand(val) ||
2092       parseAtomicOrdering(parser, result, "success_ordering") ||
2093       parseAtomicOrdering(parser, result, "failure_ordering") ||
2094       parser.parseOptionalAttrDict(result.attributes) ||
2095       parser.parseColonType(type) ||
2096       parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type),
2097                             result.operands) ||
2098       parser.resolveOperand(cmp, type, result.operands) ||
2099       parser.resolveOperand(val, type, result.operands))
2100     return failure();
2101 
2102   auto boolType = IntegerType::get(builder.getContext(), 1);
2103   auto resultType =
2104       LLVMStructType::getLiteral(builder.getContext(), {type, boolType});
2105   result.addTypes(resultType);
2106 
2107   return success();
2108 }
2109 
2110 static LogicalResult verify(AtomicCmpXchgOp op) {
2111   auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>();
2112   if (!ptrType)
2113     return op.emitOpError("expected LLVM IR pointer type for operand #0");
2114   auto cmpType = op.cmp().getType();
2115   auto valType = op.val().getType();
2116   if (cmpType != ptrType.getElementType() || cmpType != valType)
2117     return op.emitOpError("expected LLVM IR element type for operand #0 to "
2118                           "match type for all other operands");
2119   auto intType = valType.dyn_cast<IntegerType>();
2120   unsigned intBitWidth = intType ? intType.getWidth() : 0;
2121   if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 &&
2122       intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 &&
2123       !valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() &&
2124       !valType.isa<Float32Type>() && !valType.isa<Float64Type>())
2125     return op.emitOpError("unexpected LLVM IR type");
2126   if (op.success_ordering() < AtomicOrdering::monotonic ||
2127       op.failure_ordering() < AtomicOrdering::monotonic)
2128     return op.emitOpError("ordering must be at least 'monotonic'");
2129   if (op.failure_ordering() == AtomicOrdering::release ||
2130       op.failure_ordering() == AtomicOrdering::acq_rel)
2131     return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
2132   return success();
2133 }
2134 
2135 //===----------------------------------------------------------------------===//
2136 // Printer, parser and verifier for LLVM::FenceOp.
2137 //===----------------------------------------------------------------------===//
2138 
2139 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword
2140 // attribute-dict?
2141 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) {
2142   StringAttr sScope;
2143   StringRef syncscopeKeyword = "syncscope";
2144   if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) {
2145     if (parser.parseLParen() ||
2146         parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) ||
2147         parser.parseRParen())
2148       return failure();
2149   } else {
2150     result.addAttribute(syncscopeKeyword,
2151                         parser.getBuilder().getStringAttr(""));
2152   }
2153   if (parseAtomicOrdering(parser, result, "ordering") ||
2154       parser.parseOptionalAttrDict(result.attributes))
2155     return failure();
2156   return success();
2157 }
2158 
2159 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) {
2160   StringRef syncscopeKeyword = "syncscope";
2161   p << ' ';
2162   if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty())
2163     p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") ";
2164   p << stringifyAtomicOrdering(op.ordering());
2165 }
2166 
2167 static LogicalResult verify(FenceOp &op) {
2168   if (op.ordering() == AtomicOrdering::not_atomic ||
2169       op.ordering() == AtomicOrdering::unordered ||
2170       op.ordering() == AtomicOrdering::monotonic)
2171     return op.emitOpError("can be given only acquire, release, acq_rel, "
2172                           "and seq_cst orderings");
2173   return success();
2174 }
2175 
2176 //===----------------------------------------------------------------------===//
2177 // LLVMDialect initialization, type parsing, and registration.
2178 //===----------------------------------------------------------------------===//
2179 
2180 void LLVMDialect::initialize() {
2181   addAttributes<FMFAttr, LinkageAttr, LoopOptionsAttr>();
2182 
2183   // clang-format off
2184   addTypes<LLVMVoidType,
2185            LLVMPPCFP128Type,
2186            LLVMX86MMXType,
2187            LLVMTokenType,
2188            LLVMLabelType,
2189            LLVMMetadataType,
2190            LLVMFunctionType,
2191            LLVMPointerType,
2192            LLVMFixedVectorType,
2193            LLVMScalableVectorType,
2194            LLVMArrayType,
2195            LLVMStructType>();
2196   // clang-format on
2197   addOperations<
2198 #define GET_OP_LIST
2199 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2200       >();
2201 
2202   // Support unknown operations because not all LLVM operations are registered.
2203   allowUnknownOperations();
2204 }
2205 
2206 #define GET_OP_CLASSES
2207 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
2208 
2209 /// Parse a type registered to this dialect.
2210 Type LLVMDialect::parseType(DialectAsmParser &parser) const {
2211   return detail::parseType(parser);
2212 }
2213 
2214 /// Print a type registered to this dialect.
2215 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const {
2216   return detail::printType(type, os);
2217 }
2218 
2219 LogicalResult LLVMDialect::verifyDataLayoutString(
2220     StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
2221   llvm::Expected<llvm::DataLayout> maybeDataLayout =
2222       llvm::DataLayout::parse(descr);
2223   if (maybeDataLayout)
2224     return success();
2225 
2226   std::string message;
2227   llvm::raw_string_ostream messageStream(message);
2228   llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
2229   reportError("invalid data layout descriptor: " + messageStream.str());
2230   return failure();
2231 }
2232 
2233 /// Verify LLVM dialect attributes.
2234 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
2235                                                     NamedAttribute attr) {
2236   // If the `llvm.loop` attribute is present, enforce the following structure,
2237   // which the module translation can assume.
2238   if (attr.first.strref() == LLVMDialect::getLoopAttrName()) {
2239     auto loopAttr = attr.second.dyn_cast<DictionaryAttr>();
2240     if (!loopAttr)
2241       return op->emitOpError() << "expected '" << LLVMDialect::getLoopAttrName()
2242                                << "' to be a dictionary attribute";
2243     Optional<NamedAttribute> parallelAccessGroup =
2244         loopAttr.getNamed(LLVMDialect::getParallelAccessAttrName());
2245     if (parallelAccessGroup.hasValue()) {
2246       auto accessGroups = parallelAccessGroup->second.dyn_cast<ArrayAttr>();
2247       if (!accessGroups)
2248         return op->emitOpError()
2249                << "expected '" << LLVMDialect::getParallelAccessAttrName()
2250                << "' to be an array attribute";
2251       for (Attribute attr : accessGroups) {
2252         auto accessGroupRef = attr.dyn_cast<SymbolRefAttr>();
2253         if (!accessGroupRef)
2254           return op->emitOpError()
2255                  << "expected '" << attr << "' to be a symbol reference";
2256         StringAttr metadataName = accessGroupRef.getRootReference();
2257         auto metadataOp =
2258             SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>(
2259                 op->getParentOp(), metadataName);
2260         if (!metadataOp)
2261           return op->emitOpError()
2262                  << "expected '" << attr << "' to reference a metadata op";
2263         StringAttr accessGroupName = accessGroupRef.getLeafReference();
2264         Operation *accessGroupOp =
2265             SymbolTable::lookupNearestSymbolFrom(metadataOp, accessGroupName);
2266         if (!accessGroupOp)
2267           return op->emitOpError()
2268                  << "expected '" << attr << "' to reference an access_group op";
2269       }
2270     }
2271 
2272     Optional<NamedAttribute> loopOptions =
2273         loopAttr.getNamed(LLVMDialect::getLoopOptionsAttrName());
2274     if (loopOptions.hasValue() && !loopOptions->second.isa<LoopOptionsAttr>())
2275       return op->emitOpError()
2276              << "expected '" << LLVMDialect::getLoopOptionsAttrName()
2277              << "' to be a `loopopts` attribute";
2278   }
2279 
2280   // If the data layout attribute is present, it must use the LLVM data layout
2281   // syntax. Try parsing it and report errors in case of failure. Users of this
2282   // attribute may assume it is well-formed and can pass it to the (asserting)
2283   // llvm::DataLayout constructor.
2284   if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName())
2285     return success();
2286   if (auto stringAttr = attr.second.dyn_cast<StringAttr>())
2287     return verifyDataLayoutString(
2288         stringAttr.getValue(),
2289         [op](const Twine &message) { op->emitOpError() << message.str(); });
2290 
2291   return op->emitOpError() << "expected '"
2292                            << LLVM::LLVMDialect::getDataLayoutAttrName()
2293                            << "' to be a string attribute";
2294 }
2295 
2296 /// Verify LLVMIR function argument attributes.
2297 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
2298                                                     unsigned regionIdx,
2299                                                     unsigned argIdx,
2300                                                     NamedAttribute argAttr) {
2301   // Check that llvm.noalias is a unit attribute.
2302   if (argAttr.first == LLVMDialect::getNoAliasAttrName() &&
2303       !argAttr.second.isa<UnitAttr>())
2304     return op->emitError()
2305            << "expected llvm.noalias argument attribute to be a unit attribute";
2306   // Check that llvm.align is an integer attribute.
2307   if (argAttr.first == LLVMDialect::getAlignAttrName() &&
2308       !argAttr.second.isa<IntegerAttr>())
2309     return op->emitError()
2310            << "llvm.align argument attribute of non integer type";
2311   return success();
2312 }
2313 
2314 //===----------------------------------------------------------------------===//
2315 // Utility functions.
2316 //===----------------------------------------------------------------------===//
2317 
2318 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
2319                                      StringRef name, StringRef value,
2320                                      LLVM::Linkage linkage) {
2321   assert(builder.getInsertionBlock() &&
2322          builder.getInsertionBlock()->getParentOp() &&
2323          "expected builder to point to a block constrained in an op");
2324   auto module =
2325       builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
2326   assert(module && "builder points to an op outside of a module");
2327 
2328   // Create the global at the entry of the module.
2329   OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener());
2330   MLIRContext *ctx = builder.getContext();
2331   auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size());
2332   auto global = moduleBuilder.create<LLVM::GlobalOp>(
2333       loc, type, /*isConstant=*/true, linkage, name,
2334       builder.getStringAttr(value), /*alignment=*/0);
2335 
2336   // Get the pointer to the first character in the global string.
2337   Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
2338   Value cst0 = builder.create<LLVM::ConstantOp>(
2339       loc, IntegerType::get(ctx, 64),
2340       builder.getIntegerAttr(builder.getIndexType(), 0));
2341   return builder.create<LLVM::GEPOp>(
2342       loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr,
2343       ValueRange{cst0, cst0});
2344 }
2345 
2346 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
2347   return op->hasTrait<OpTrait::SymbolTable>() &&
2348          op->hasTrait<OpTrait::IsIsolatedFromAbove>();
2349 }
2350 
2351 static constexpr const FastmathFlags FastmathFlagsList[] = {
2352     // clang-format off
2353     FastmathFlags::nnan,
2354     FastmathFlags::ninf,
2355     FastmathFlags::nsz,
2356     FastmathFlags::arcp,
2357     FastmathFlags::contract,
2358     FastmathFlags::afn,
2359     FastmathFlags::reassoc,
2360     FastmathFlags::fast,
2361     // clang-format on
2362 };
2363 
2364 void FMFAttr::print(DialectAsmPrinter &printer) const {
2365   printer << "fastmath<";
2366   auto flags = llvm::make_filter_range(FastmathFlagsList, [&](auto flag) {
2367     return bitEnumContains(this->getFlags(), flag);
2368   });
2369   llvm::interleaveComma(flags, printer,
2370                         [&](auto flag) { printer << stringifyEnum(flag); });
2371   printer << ">";
2372 }
2373 
2374 Attribute FMFAttr::parse(MLIRContext *context, DialectAsmParser &parser,
2375                          Type type) {
2376   if (failed(parser.parseLess()))
2377     return {};
2378 
2379   FastmathFlags flags = {};
2380   if (failed(parser.parseOptionalGreater())) {
2381     do {
2382       StringRef elemName;
2383       if (failed(parser.parseKeyword(&elemName)))
2384         return {};
2385 
2386       auto elem = symbolizeFastmathFlags(elemName);
2387       if (!elem) {
2388         parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ")
2389             << elemName;
2390         return {};
2391       }
2392 
2393       flags = flags | *elem;
2394     } while (succeeded(parser.parseOptionalComma()));
2395 
2396     if (failed(parser.parseGreater()))
2397       return {};
2398   }
2399 
2400   return FMFAttr::get(parser.getBuilder().getContext(), flags);
2401 }
2402 
2403 void LinkageAttr::print(DialectAsmPrinter &printer) const {
2404   printer << "linkage<";
2405   if (static_cast<uint64_t>(getLinkage()) <= getMaxEnumValForLinkage())
2406     printer << stringifyEnum(getLinkage());
2407   else
2408     printer << static_cast<uint64_t>(getLinkage());
2409   printer << ">";
2410 }
2411 
2412 Attribute LinkageAttr::parse(MLIRContext *context, DialectAsmParser &parser,
2413                              Type type) {
2414   StringRef elemName;
2415   if (parser.parseLess() || parser.parseKeyword(&elemName) ||
2416       parser.parseGreater())
2417     return {};
2418   auto elem = linkage::symbolizeLinkage(elemName);
2419   if (!elem) {
2420     parser.emitError(parser.getNameLoc(), "Unknown linkage: ") << elemName;
2421     return {};
2422   }
2423   Linkage linkage = *elem;
2424   return LinkageAttr::get(context, linkage);
2425 }
2426 
2427 LoopOptionsAttrBuilder::LoopOptionsAttrBuilder(LoopOptionsAttr attr)
2428     : options(attr.getOptions().begin(), attr.getOptions().end()) {}
2429 
2430 template <typename T>
2431 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setOption(LoopOptionCase tag,
2432                                                           Optional<T> value) {
2433   auto option = llvm::find_if(
2434       options, [tag](auto option) { return option.first == tag; });
2435   if (option != options.end()) {
2436     if (value.hasValue())
2437       option->second = *value;
2438     else
2439       options.erase(option);
2440   } else {
2441     options.push_back(LoopOptionsAttr::OptionValuePair(tag, *value));
2442   }
2443   return *this;
2444 }
2445 
2446 LoopOptionsAttrBuilder &
2447 LoopOptionsAttrBuilder::setDisableLICM(Optional<bool> value) {
2448   return setOption(LoopOptionCase::disable_licm, value);
2449 }
2450 
2451 /// Set the `interleave_count` option to the provided value. If no value
2452 /// is provided the option is deleted.
2453 LoopOptionsAttrBuilder &
2454 LoopOptionsAttrBuilder::setInterleaveCount(Optional<uint64_t> count) {
2455   return setOption(LoopOptionCase::interleave_count, count);
2456 }
2457 
2458 /// Set the `disable_unroll` option to the provided value. If no value
2459 /// is provided the option is deleted.
2460 LoopOptionsAttrBuilder &
2461 LoopOptionsAttrBuilder::setDisableUnroll(Optional<bool> value) {
2462   return setOption(LoopOptionCase::disable_unroll, value);
2463 }
2464 
2465 /// Set the `disable_pipeline` option to the provided value. If no value
2466 /// is provided the option is deleted.
2467 LoopOptionsAttrBuilder &
2468 LoopOptionsAttrBuilder::setDisablePipeline(Optional<bool> value) {
2469   return setOption(LoopOptionCase::disable_pipeline, value);
2470 }
2471 
2472 /// Set the `pipeline_initiation_interval` option to the provided value.
2473 /// If no value is provided the option is deleted.
2474 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setPipelineInitiationInterval(
2475     Optional<uint64_t> count) {
2476   return setOption(LoopOptionCase::pipeline_initiation_interval, count);
2477 }
2478 
2479 template <typename T>
2480 static Optional<T>
2481 getOption(ArrayRef<std::pair<LoopOptionCase, int64_t>> options,
2482           LoopOptionCase option) {
2483   auto it =
2484       lower_bound(options, option, [](auto optionPair, LoopOptionCase option) {
2485         return optionPair.first < option;
2486       });
2487   if (it == options.end())
2488     return {};
2489   return static_cast<T>(it->second);
2490 }
2491 
2492 Optional<bool> LoopOptionsAttr::disableUnroll() {
2493   return getOption<bool>(getOptions(), LoopOptionCase::disable_unroll);
2494 }
2495 
2496 Optional<bool> LoopOptionsAttr::disableLICM() {
2497   return getOption<bool>(getOptions(), LoopOptionCase::disable_licm);
2498 }
2499 
2500 Optional<int64_t> LoopOptionsAttr::interleaveCount() {
2501   return getOption<int64_t>(getOptions(), LoopOptionCase::interleave_count);
2502 }
2503 
2504 /// Build the LoopOptions Attribute from a sorted array of individual options.
2505 LoopOptionsAttr LoopOptionsAttr::get(
2506     MLIRContext *context,
2507     ArrayRef<std::pair<LoopOptionCase, int64_t>> sortedOptions) {
2508   assert(llvm::is_sorted(sortedOptions, llvm::less_first()) &&
2509          "LoopOptionsAttr ctor expects a sorted options array");
2510   return Base::get(context, sortedOptions);
2511 }
2512 
2513 /// Build the LoopOptions Attribute from a sorted array of individual options.
2514 LoopOptionsAttr LoopOptionsAttr::get(MLIRContext *context,
2515                                      LoopOptionsAttrBuilder &optionBuilders) {
2516   llvm::sort(optionBuilders.options, llvm::less_first());
2517   return Base::get(context, optionBuilders.options);
2518 }
2519 
2520 void LoopOptionsAttr::print(DialectAsmPrinter &printer) const {
2521   printer << getMnemonic() << "<";
2522   llvm::interleaveComma(getOptions(), printer, [&](auto option) {
2523     printer << stringifyEnum(option.first) << " = ";
2524     switch (option.first) {
2525     case LoopOptionCase::disable_licm:
2526     case LoopOptionCase::disable_unroll:
2527     case LoopOptionCase::disable_pipeline:
2528       printer << (option.second ? "true" : "false");
2529       break;
2530     case LoopOptionCase::interleave_count:
2531     case LoopOptionCase::pipeline_initiation_interval:
2532       printer << option.second;
2533       break;
2534     }
2535   });
2536   printer << ">";
2537 }
2538 
2539 Attribute LoopOptionsAttr::parse(MLIRContext *context, DialectAsmParser &parser,
2540                                  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.getBuilder().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 =
2608         generatedAttributeParser(getContext(), parser, attrKind, type, attr);
2609     if (parseResult.hasValue())
2610       return attr;
2611   }
2612   parser.emitError(parser.getNameLoc(), "unknown attribute type: ") << attrKind;
2613   return {};
2614 }
2615 
2616 void LLVMDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
2617   if (succeeded(generatedAttributePrinter(attr, os)))
2618     return;
2619   llvm_unreachable("Unknown attribute type");
2620 }
2621