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