MLIR  22.0.0git
LLVMDialect.cpp
Go to the documentation of this file.
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 
17 #include "mlir/IR/Attributes.h"
18 #include "mlir/IR/Builders.h"
19 #include "mlir/IR/BuiltinOps.h"
20 #include "mlir/IR/BuiltinTypes.h"
22 #include "mlir/IR/MLIRContext.h"
23 #include "mlir/IR/Matchers.h"
26 
27 #include "llvm/ADT/APFloat.h"
28 #include "llvm/ADT/TypeSwitch.h"
29 #include "llvm/IR/DataLayout.h"
30 #include "llvm/Support/Error.h"
31 
32 #include "LLVMDialectBytecode.h"
33 
34 #include <numeric>
35 #include <optional>
36 
37 using namespace mlir;
38 using namespace mlir::LLVM;
39 using mlir::LLVM::cconv::getMaxEnumValForCConv;
40 using mlir::LLVM::linkage::getMaxEnumValForLinkage;
41 using mlir::LLVM::tailcallkind::getMaxEnumValForTailCallKind;
42 
43 #include "mlir/Dialect/LLVMIR/LLVMOpsDialect.cpp.inc"
44 
45 //===----------------------------------------------------------------------===//
46 // Attribute Helpers
47 //===----------------------------------------------------------------------===//
48 
49 static constexpr const char kElemTypeAttrName[] = "elem_type";
50 
52  SmallVector<NamedAttribute, 8> filteredAttrs(
53  llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
54  if (attr.getName() == "fastmathFlags") {
55  auto defAttr =
56  FastmathFlagsAttr::get(attr.getValue().getContext(), {});
57  return defAttr != attr.getValue();
58  }
59  return true;
60  }));
61  return filteredAttrs;
62 }
63 
64 /// Verifies `symbol`'s use in `op` to ensure the symbol is a valid and
65 /// fully defined llvm.func.
66 static LogicalResult verifySymbolAttrUse(FlatSymbolRefAttr symbol,
67  Operation *op,
68  SymbolTableCollection &symbolTable) {
69  StringRef name = symbol.getValue();
70  auto func =
71  symbolTable.lookupNearestSymbolFrom<LLVMFuncOp>(op, symbol.getAttr());
72  if (!func)
73  return op->emitOpError("'")
74  << name << "' does not reference a valid LLVM function";
75  if (func.isExternal())
76  return op->emitOpError("'") << name << "' does not have a definition";
77  return success();
78 }
79 
80 /// Returns a boolean type that has the same shape as `type`. It supports both
81 /// fixed size vectors as well as scalable vectors.
82 static Type getI1SameShape(Type type) {
83  Type i1Type = IntegerType::get(type.getContext(), 1);
85  return LLVM::getVectorType(i1Type, LLVM::getVectorNumElements(type));
86  return i1Type;
87 }
88 
89 // Parses one of the keywords provided in the list `keywords` and returns the
90 // position of the parsed keyword in the list. If none of the keywords from the
91 // list is parsed, returns -1.
93  ArrayRef<StringRef> keywords) {
94  for (const auto &en : llvm::enumerate(keywords)) {
95  if (succeeded(parser.parseOptionalKeyword(en.value())))
96  return en.index();
97  }
98  return -1;
99 }
100 
101 namespace {
102 template <typename Ty>
103 struct EnumTraits {};
104 
105 #define REGISTER_ENUM_TYPE(Ty) \
106  template <> \
107  struct EnumTraits<Ty> { \
108  static StringRef stringify(Ty value) { return stringify##Ty(value); } \
109  static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \
110  }
111 
112 REGISTER_ENUM_TYPE(Linkage);
113 REGISTER_ENUM_TYPE(UnnamedAddr);
114 REGISTER_ENUM_TYPE(CConv);
115 REGISTER_ENUM_TYPE(TailCallKind);
117 } // namespace
118 
119 /// Parse an enum from the keyword, or default to the provided default value.
120 /// The return type is the enum type by default, unless overridden with the
121 /// second template argument.
122 template <typename EnumTy, typename RetTy = EnumTy>
124  EnumTy defaultValue) {
126  for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i)
127  names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));
128 
129  int index = parseOptionalKeywordAlternative(parser, names);
130  if (index == -1)
131  return static_cast<RetTy>(defaultValue);
132  return static_cast<RetTy>(index);
133 }
134 
135 static void printLLVMLinkage(OpAsmPrinter &p, Operation *, LinkageAttr val) {
136  p << stringifyLinkage(val.getLinkage());
137 }
138 
139 static ParseResult parseLLVMLinkage(OpAsmParser &p, LinkageAttr &val) {
140  val = LinkageAttr::get(
141  p.getContext(),
142  parseOptionalLLVMKeyword<LLVM::Linkage>(p, LLVM::Linkage::External));
143  return success();
144 }
145 
147  bool isExpandLoad,
148  uint64_t alignment = 1) {
149  // From
150  // https://llvm.org/docs/LangRef.html#llvm-masked-expandload-intrinsics
151  // https://llvm.org/docs/LangRef.html#llvm-masked-compressstore-intrinsics
152  //
153  // The pointer alignment defaults to 1.
154  if (alignment == 1) {
155  return nullptr;
156  }
157 
158  auto emptyDictAttr = builder.getDictionaryAttr({});
159  auto alignmentAttr = builder.getI64IntegerAttr(alignment);
160  auto namedAttr =
161  builder.getNamedAttr(LLVMDialect::getAlignAttrName(), alignmentAttr);
162  SmallVector<mlir::NamedAttribute> attrs = {namedAttr};
163  auto alignDictAttr = builder.getDictionaryAttr(attrs);
164  // From
165  // https://llvm.org/docs/LangRef.html#llvm-masked-expandload-intrinsics
166  // https://llvm.org/docs/LangRef.html#llvm-masked-compressstore-intrinsics
167  //
168  // The align parameter attribute can be provided for [expandload]'s first
169  // argument. The align parameter attribute can be provided for
170  // [compressstore]'s second argument.
171  int pos = isExpandLoad ? 0 : 1;
172  return pos == 0 ? builder.getArrayAttr(
173  {alignDictAttr, emptyDictAttr, emptyDictAttr})
174  : builder.getArrayAttr(
175  {emptyDictAttr, alignDictAttr, emptyDictAttr});
176 }
177 
178 //===----------------------------------------------------------------------===//
179 // Operand bundle helpers.
180 //===----------------------------------------------------------------------===//
181 
182 static void printOneOpBundle(OpAsmPrinter &p, OperandRange operands,
183  TypeRange operandTypes, StringRef tag) {
184  p.printString(tag);
185  p << "(";
186 
187  if (!operands.empty()) {
188  p.printOperands(operands);
189  p << " : ";
190  llvm::interleaveComma(operandTypes, p);
191  }
192 
193  p << ")";
194 }
195 
197  OperandRangeRange opBundleOperands,
198  TypeRangeRange opBundleOperandTypes,
199  std::optional<ArrayAttr> opBundleTags) {
200  if (opBundleOperands.empty())
201  return;
202  assert(opBundleTags && "expect operand bundle tags");
203 
204  p << "[";
205  llvm::interleaveComma(
206  llvm::zip(opBundleOperands, opBundleOperandTypes, *opBundleTags), p,
207  [&p](auto bundle) {
208  auto bundleTag = cast<StringAttr>(std::get<2>(bundle)).getValue();
209  printOneOpBundle(p, std::get<0>(bundle), std::get<1>(bundle),
210  bundleTag);
211  });
212  p << "]";
213 }
214 
215 static ParseResult parseOneOpBundle(
216  OpAsmParser &p,
218  SmallVector<SmallVector<Type>> &opBundleOperandTypes,
219  SmallVector<Attribute> &opBundleTags) {
220  SMLoc currentParserLoc = p.getCurrentLocation();
222  SmallVector<Type> types;
223  std::string tag;
224 
225  if (p.parseString(&tag))
226  return p.emitError(currentParserLoc, "expect operand bundle tag");
227 
228  if (p.parseLParen())
229  return failure();
230 
231  if (p.parseOptionalRParen()) {
232  if (p.parseOperandList(operands) || p.parseColon() ||
233  p.parseTypeList(types) || p.parseRParen())
234  return failure();
235  }
236 
237  opBundleOperands.push_back(std::move(operands));
238  opBundleOperandTypes.push_back(std::move(types));
239  opBundleTags.push_back(StringAttr::get(p.getContext(), tag));
240 
241  return success();
242 }
243 
244 static std::optional<ParseResult> parseOpBundles(
245  OpAsmParser &p,
247  SmallVector<SmallVector<Type>> &opBundleOperandTypes,
248  ArrayAttr &opBundleTags) {
249  if (p.parseOptionalLSquare())
250  return std::nullopt;
251 
252  if (succeeded(p.parseOptionalRSquare()))
253  return success();
254 
255  SmallVector<Attribute> opBundleTagAttrs;
256  auto bundleParser = [&] {
257  return parseOneOpBundle(p, opBundleOperands, opBundleOperandTypes,
258  opBundleTagAttrs);
259  };
260  if (p.parseCommaSeparatedList(bundleParser))
261  return failure();
262 
263  if (p.parseRSquare())
264  return failure();
265 
266  opBundleTags = ArrayAttr::get(p.getContext(), opBundleTagAttrs);
267 
268  return success();
269 }
270 
271 //===----------------------------------------------------------------------===//
272 // Printing, parsing, folding and builder for LLVM::CmpOp.
273 //===----------------------------------------------------------------------===//
274 
275 void ICmpOp::print(OpAsmPrinter &p) {
276  p << " \"" << stringifyICmpPredicate(getPredicate()) << "\" " << getOperand(0)
277  << ", " << getOperand(1);
278  p.printOptionalAttrDict((*this)->getAttrs(), {"predicate"});
279  p << " : " << getLhs().getType();
280 }
281 
282 void FCmpOp::print(OpAsmPrinter &p) {
283  p << " \"" << stringifyFCmpPredicate(getPredicate()) << "\" " << getOperand(0)
284  << ", " << getOperand(1);
285  p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"predicate"});
286  p << " : " << getLhs().getType();
287 }
288 
289 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
290 // attribute-dict? `:` type
291 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use
292 // attribute-dict? `:` type
293 template <typename CmpPredicateType>
294 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) {
295  StringAttr predicateAttr;
297  Type type;
298  SMLoc predicateLoc, trailingTypeLoc;
299  if (parser.getCurrentLocation(&predicateLoc) ||
300  parser.parseAttribute(predicateAttr, "predicate", result.attributes) ||
301  parser.parseOperand(lhs) || parser.parseComma() ||
302  parser.parseOperand(rhs) ||
303  parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
304  parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) ||
305  parser.resolveOperand(lhs, type, result.operands) ||
306  parser.resolveOperand(rhs, type, result.operands))
307  return failure();
308 
309  // Replace the string attribute `predicate` with an integer attribute.
310  int64_t predicateValue = 0;
311  if (std::is_same<CmpPredicateType, ICmpPredicate>()) {
312  std::optional<ICmpPredicate> predicate =
313  symbolizeICmpPredicate(predicateAttr.getValue());
314  if (!predicate)
315  return parser.emitError(predicateLoc)
316  << "'" << predicateAttr.getValue()
317  << "' is an incorrect value of the 'predicate' attribute";
318  predicateValue = static_cast<int64_t>(*predicate);
319  } else {
320  std::optional<FCmpPredicate> predicate =
321  symbolizeFCmpPredicate(predicateAttr.getValue());
322  if (!predicate)
323  return parser.emitError(predicateLoc)
324  << "'" << predicateAttr.getValue()
325  << "' is an incorrect value of the 'predicate' attribute";
326  predicateValue = static_cast<int64_t>(*predicate);
327  }
328 
329  result.attributes.set("predicate",
330  parser.getBuilder().getI64IntegerAttr(predicateValue));
331 
332  // The result type is either i1 or a vector type <? x i1> if the inputs are
333  // vectors.
334  if (!isCompatibleType(type))
335  return parser.emitError(trailingTypeLoc,
336  "expected LLVM dialect-compatible type");
337  result.addTypes(getI1SameShape(type));
338  return success();
339 }
340 
341 ParseResult ICmpOp::parse(OpAsmParser &parser, OperationState &result) {
342  return parseCmpOp<ICmpPredicate>(parser, result);
343 }
344 
345 ParseResult FCmpOp::parse(OpAsmParser &parser, OperationState &result) {
346  return parseCmpOp<FCmpPredicate>(parser, result);
347 }
348 
349 /// Returns a scalar or vector boolean attribute of the given type.
350 static Attribute getBoolAttribute(Type type, MLIRContext *ctx, bool value) {
351  auto boolAttr = BoolAttr::get(ctx, value);
352  ShapedType shapedType = dyn_cast<ShapedType>(type);
353  if (!shapedType)
354  return boolAttr;
355  return DenseElementsAttr::get(shapedType, boolAttr);
356 }
357 
358 OpFoldResult ICmpOp::fold(FoldAdaptor adaptor) {
359  if (getPredicate() != ICmpPredicate::eq &&
360  getPredicate() != ICmpPredicate::ne)
361  return {};
362 
363  // cmpi(eq/ne, x, x) -> true/false
364  if (getLhs() == getRhs())
365  return getBoolAttribute(getType(), getContext(),
366  getPredicate() == ICmpPredicate::eq);
367 
368  // cmpi(eq/ne, alloca, null) -> false/true
369  if (getLhs().getDefiningOp<AllocaOp>() && getRhs().getDefiningOp<ZeroOp>())
370  return getBoolAttribute(getType(), getContext(),
371  getPredicate() == ICmpPredicate::ne);
372 
373  // cmpi(eq/ne, null, alloca) -> cmpi(eq/ne, alloca, null)
374  if (getLhs().getDefiningOp<ZeroOp>() && getRhs().getDefiningOp<AllocaOp>()) {
375  Value lhs = getLhs();
376  Value rhs = getRhs();
377  getLhsMutable().assign(rhs);
378  getRhsMutable().assign(lhs);
379  return getResult();
380  }
381 
382  return {};
383 }
384 
385 //===----------------------------------------------------------------------===//
386 // Printing, parsing and verification for LLVM::AllocaOp.
387 //===----------------------------------------------------------------------===//
388 
389 void AllocaOp::print(OpAsmPrinter &p) {
390  auto funcTy =
391  FunctionType::get(getContext(), {getArraySize().getType()}, {getType()});
392 
393  if (getInalloca())
394  p << " inalloca";
395 
396  p << ' ' << getArraySize() << " x " << getElemType();
397  if (getAlignment() && *getAlignment() != 0)
398  p.printOptionalAttrDict((*this)->getAttrs(),
399  {kElemTypeAttrName, getInallocaAttrName()});
400  else
402  (*this)->getAttrs(),
403  {getAlignmentAttrName(), kElemTypeAttrName, getInallocaAttrName()});
404  p << " : " << funcTy;
405 }
406 
407 // <operation> ::= `llvm.alloca` `inalloca`? ssa-use `x` type
408 // attribute-dict? `:` type `,` type
409 ParseResult AllocaOp::parse(OpAsmParser &parser, OperationState &result) {
411  Type type, elemType;
412  SMLoc trailingTypeLoc;
413 
414  if (succeeded(parser.parseOptionalKeyword("inalloca")))
415  result.addAttribute(getInallocaAttrName(result.name),
416  UnitAttr::get(parser.getContext()));
417 
418  if (parser.parseOperand(arraySize) || parser.parseKeyword("x") ||
419  parser.parseType(elemType) ||
420  parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
421  parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type))
422  return failure();
423 
424  std::optional<NamedAttribute> alignmentAttr =
425  result.attributes.getNamed("alignment");
426  if (alignmentAttr.has_value()) {
427  auto alignmentInt = llvm::dyn_cast<IntegerAttr>(alignmentAttr->getValue());
428  if (!alignmentInt)
429  return parser.emitError(parser.getNameLoc(),
430  "expected integer alignment");
431  if (alignmentInt.getValue().isZero())
432  result.attributes.erase("alignment");
433  }
434 
435  // Extract the result type from the trailing function type.
436  auto funcType = llvm::dyn_cast<FunctionType>(type);
437  if (!funcType || funcType.getNumInputs() != 1 ||
438  funcType.getNumResults() != 1)
439  return parser.emitError(
440  trailingTypeLoc,
441  "expected trailing function type with one argument and one result");
442 
443  if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands))
444  return failure();
445 
446  Type resultType = funcType.getResult(0);
447  if (auto ptrResultType = llvm::dyn_cast<LLVMPointerType>(resultType))
448  result.addAttribute(kElemTypeAttrName, TypeAttr::get(elemType));
449 
450  result.addTypes({funcType.getResult(0)});
451  return success();
452 }
453 
454 LogicalResult AllocaOp::verify() {
455  // Only certain target extension types can be used in 'alloca'.
456  if (auto targetExtType = dyn_cast<LLVMTargetExtType>(getElemType());
457  targetExtType && !targetExtType.supportsMemOps())
458  return emitOpError()
459  << "this target extension type cannot be used in alloca";
460 
461  return success();
462 }
463 
464 //===----------------------------------------------------------------------===//
465 // LLVM::BrOp
466 //===----------------------------------------------------------------------===//
467 
469  assert(index == 0 && "invalid successor index");
470  return SuccessorOperands(getDestOperandsMutable());
471 }
472 
473 //===----------------------------------------------------------------------===//
474 // LLVM::CondBrOp
475 //===----------------------------------------------------------------------===//
476 
478  assert(index < getNumSuccessors() && "invalid successor index");
479  return SuccessorOperands(index == 0 ? getTrueDestOperandsMutable()
480  : getFalseDestOperandsMutable());
481 }
482 
483 void CondBrOp::build(OpBuilder &builder, OperationState &result,
484  Value condition, Block *trueDest, ValueRange trueOperands,
485  Block *falseDest, ValueRange falseOperands,
486  std::optional<std::pair<uint32_t, uint32_t>> weights) {
487  DenseI32ArrayAttr weightsAttr;
488  if (weights)
489  weightsAttr =
490  builder.getDenseI32ArrayAttr({static_cast<int32_t>(weights->first),
491  static_cast<int32_t>(weights->second)});
492 
493  build(builder, result, condition, trueOperands, falseOperands, weightsAttr,
494  /*loop_annotation=*/{}, trueDest, falseDest);
495 }
496 
497 //===----------------------------------------------------------------------===//
498 // LLVM::SwitchOp
499 //===----------------------------------------------------------------------===//
500 
501 void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value,
502  Block *defaultDestination, ValueRange defaultOperands,
503  DenseIntElementsAttr caseValues,
504  BlockRange caseDestinations,
505  ArrayRef<ValueRange> caseOperands,
506  ArrayRef<int32_t> branchWeights) {
507  DenseI32ArrayAttr weightsAttr;
508  if (!branchWeights.empty())
509  weightsAttr = builder.getDenseI32ArrayAttr(branchWeights);
510 
511  build(builder, result, value, defaultOperands, caseOperands, caseValues,
512  weightsAttr, defaultDestination, caseDestinations);
513 }
514 
515 void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value,
516  Block *defaultDestination, ValueRange defaultOperands,
517  ArrayRef<APInt> caseValues, BlockRange caseDestinations,
518  ArrayRef<ValueRange> caseOperands,
519  ArrayRef<int32_t> branchWeights) {
520  DenseIntElementsAttr caseValuesAttr;
521  if (!caseValues.empty()) {
522  ShapedType caseValueType = VectorType::get(
523  static_cast<int64_t>(caseValues.size()), value.getType());
524  caseValuesAttr = DenseIntElementsAttr::get(caseValueType, caseValues);
525  }
526 
527  build(builder, result, value, defaultDestination, defaultOperands,
528  caseValuesAttr, caseDestinations, caseOperands, branchWeights);
529 }
530 
531 void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value,
532  Block *defaultDestination, ValueRange defaultOperands,
533  ArrayRef<int32_t> caseValues, BlockRange caseDestinations,
534  ArrayRef<ValueRange> caseOperands,
535  ArrayRef<int32_t> branchWeights) {
536  DenseIntElementsAttr caseValuesAttr;
537  if (!caseValues.empty()) {
538  ShapedType caseValueType = VectorType::get(
539  static_cast<int64_t>(caseValues.size()), value.getType());
540  caseValuesAttr = DenseIntElementsAttr::get(caseValueType, caseValues);
541  }
542 
543  build(builder, result, value, defaultDestination, defaultOperands,
544  caseValuesAttr, caseDestinations, caseOperands, branchWeights);
545 }
546 
547 /// <cases> ::= `[` (case (`,` case )* )? `]`
548 /// <case> ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)?
549 static ParseResult parseSwitchOpCases(
550  OpAsmParser &parser, Type flagType, DenseIntElementsAttr &caseValues,
551  SmallVectorImpl<Block *> &caseDestinations,
553  SmallVectorImpl<SmallVector<Type>> &caseOperandTypes) {
554  if (failed(parser.parseLSquare()))
555  return failure();
556  if (succeeded(parser.parseOptionalRSquare()))
557  return success();
558  SmallVector<APInt> values;
559  unsigned bitWidth = flagType.getIntOrFloatBitWidth();
560  auto parseCase = [&]() {
561  int64_t value = 0;
562  if (failed(parser.parseInteger(value)))
563  return failure();
564  values.push_back(APInt(bitWidth, value, /*isSigned=*/true));
565 
566  Block *destination;
568  SmallVector<Type> operandTypes;
569  if (parser.parseColon() || parser.parseSuccessor(destination))
570  return failure();
571  if (!parser.parseOptionalLParen()) {
572  if (parser.parseOperandList(operands, OpAsmParser::Delimiter::None,
573  /*allowResultNumber=*/false) ||
574  parser.parseColonTypeList(operandTypes) || parser.parseRParen())
575  return failure();
576  }
577  caseDestinations.push_back(destination);
578  caseOperands.emplace_back(operands);
579  caseOperandTypes.emplace_back(operandTypes);
580  return success();
581  };
582  if (failed(parser.parseCommaSeparatedList(parseCase)))
583  return failure();
584 
585  ShapedType caseValueType =
586  VectorType::get(static_cast<int64_t>(values.size()), flagType);
587  caseValues = DenseIntElementsAttr::get(caseValueType, values);
588  return parser.parseRSquare();
589 }
590 
591 static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op, Type flagType,
592  DenseIntElementsAttr caseValues,
593  SuccessorRange caseDestinations,
594  OperandRangeRange caseOperands,
595  const TypeRangeRange &caseOperandTypes) {
596  p << '[';
597  p.printNewline();
598  if (!caseValues) {
599  p << ']';
600  return;
601  }
602 
603  size_t index = 0;
604  llvm::interleave(
605  llvm::zip(caseValues, caseDestinations),
606  [&](auto i) {
607  p << " ";
608  p << std::get<0>(i);
609  p << ": ";
610  p.printSuccessorAndUseList(std::get<1>(i), caseOperands[index++]);
611  },
612  [&] {
613  p << ',';
614  p.printNewline();
615  });
616  p.printNewline();
617  p << ']';
618 }
619 
620 LogicalResult SwitchOp::verify() {
621  if ((!getCaseValues() && !getCaseDestinations().empty()) ||
622  (getCaseValues() &&
623  getCaseValues()->size() !=
624  static_cast<int64_t>(getCaseDestinations().size())))
625  return emitOpError("expects number of case values to match number of "
626  "case destinations");
627  if (getCaseValues() &&
628  getValue().getType() != getCaseValues()->getElementType())
629  return emitError("expects case value type to match condition value type");
630  return success();
631 }
632 
634  assert(index < getNumSuccessors() && "invalid successor index");
635  return SuccessorOperands(index == 0 ? getDefaultOperandsMutable()
636  : getCaseOperandsMutable(index - 1));
637 }
638 
639 //===----------------------------------------------------------------------===//
640 // Code for LLVM::GEPOp.
641 //===----------------------------------------------------------------------===//
642 
643 constexpr int32_t GEPOp::kDynamicIndex;
644 
646  return GEPIndicesAdaptor<ValueRange>(getRawConstantIndicesAttr(),
647  getDynamicIndices());
648 }
649 
650 /// Returns the elemental type of any LLVM-compatible vector type or self.
652  if (auto vectorType = llvm::dyn_cast<VectorType>(type))
653  return vectorType.getElementType();
654  return type;
655 }
656 
657 /// Destructures the 'indices' parameter into 'rawConstantIndices' and
658 /// 'dynamicIndices', encoding the former in the process. In the process,
659 /// dynamic indices which are used to index into a structure type are converted
660 /// to constant indices when possible. To do this, the GEPs element type should
661 /// be passed as first parameter.
662 static void destructureIndices(Type currType, ArrayRef<GEPArg> indices,
663  SmallVectorImpl<int32_t> &rawConstantIndices,
664  SmallVectorImpl<Value> &dynamicIndices) {
665  for (const GEPArg &iter : indices) {
666  // If the thing we are currently indexing into is a struct we must turn
667  // any integer constants into constant indices. If this is not possible
668  // we don't do anything here. The verifier will catch it and emit a proper
669  // error. All other canonicalization is done in the fold method.
670  bool requiresConst = !rawConstantIndices.empty() &&
671  isa_and_nonnull<LLVMStructType>(currType);
672  if (Value val = llvm::dyn_cast_if_present<Value>(iter)) {
673  APInt intC;
674  if (requiresConst && matchPattern(val, m_ConstantInt(&intC)) &&
675  intC.isSignedIntN(kGEPConstantBitWidth)) {
676  rawConstantIndices.push_back(intC.getSExtValue());
677  } else {
678  rawConstantIndices.push_back(GEPOp::kDynamicIndex);
679  dynamicIndices.push_back(val);
680  }
681  } else {
682  rawConstantIndices.push_back(cast<GEPConstantIndex>(iter));
683  }
684 
685  // Skip for very first iteration of this loop. First index does not index
686  // within the aggregates, but is just a pointer offset.
687  if (rawConstantIndices.size() == 1 || !currType)
688  continue;
689 
690  currType = TypeSwitch<Type, Type>(currType)
691  .Case<VectorType, LLVMArrayType>([](auto containerType) {
692  return containerType.getElementType();
693  })
694  .Case([&](LLVMStructType structType) -> Type {
695  int64_t memberIndex = rawConstantIndices.back();
696  if (memberIndex >= 0 && static_cast<size_t>(memberIndex) <
697  structType.getBody().size())
698  return structType.getBody()[memberIndex];
699  return nullptr;
700  })
701  .Default(nullptr);
702  }
703 }
704 
705 void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
706  Type elementType, Value basePtr, ArrayRef<GEPArg> indices,
707  GEPNoWrapFlags noWrapFlags,
708  ArrayRef<NamedAttribute> attributes) {
709  SmallVector<int32_t> rawConstantIndices;
710  SmallVector<Value> dynamicIndices;
711  destructureIndices(elementType, indices, rawConstantIndices, dynamicIndices);
712 
713  result.addTypes(resultType);
714  result.addAttributes(attributes);
715  result.getOrAddProperties<Properties>().rawConstantIndices =
716  builder.getDenseI32ArrayAttr(rawConstantIndices);
717  result.getOrAddProperties<Properties>().noWrapFlags = noWrapFlags;
718  result.getOrAddProperties<Properties>().elem_type =
719  TypeAttr::get(elementType);
720  result.addOperands(basePtr);
721  result.addOperands(dynamicIndices);
722 }
723 
724 void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType,
725  Type elementType, Value basePtr, ValueRange indices,
726  GEPNoWrapFlags noWrapFlags,
727  ArrayRef<NamedAttribute> attributes) {
728  build(builder, result, resultType, elementType, basePtr,
729  SmallVector<GEPArg>(indices), noWrapFlags, attributes);
730 }
731 
732 static ParseResult
735  DenseI32ArrayAttr &rawConstantIndices) {
736  SmallVector<int32_t> constantIndices;
737 
738  auto idxParser = [&]() -> ParseResult {
739  int32_t constantIndex;
740  OptionalParseResult parsedInteger =
742  if (parsedInteger.has_value()) {
743  if (failed(parsedInteger.value()))
744  return failure();
745  constantIndices.push_back(constantIndex);
746  return success();
747  }
748 
749  constantIndices.push_back(LLVM::GEPOp::kDynamicIndex);
750  return parser.parseOperand(indices.emplace_back());
751  };
752  if (parser.parseCommaSeparatedList(idxParser))
753  return failure();
754 
755  rawConstantIndices =
756  DenseI32ArrayAttr::get(parser.getContext(), constantIndices);
757  return success();
758 }
759 
760 static void printGEPIndices(OpAsmPrinter &printer, LLVM::GEPOp gepOp,
761  OperandRange indices,
762  DenseI32ArrayAttr rawConstantIndices) {
763  llvm::interleaveComma(
764  GEPIndicesAdaptor<OperandRange>(rawConstantIndices, indices), printer,
766  if (Value val = llvm::dyn_cast_if_present<Value>(cst))
767  printer.printOperand(val);
768  else
769  printer << cast<IntegerAttr>(cst).getInt();
770  });
771 }
772 
773 /// For the given `indices`, check if they comply with `baseGEPType`,
774 /// especially check against LLVMStructTypes nested within.
775 static LogicalResult
776 verifyStructIndices(Type baseGEPType, unsigned indexPos,
778  function_ref<InFlightDiagnostic()> emitOpError) {
779  if (indexPos >= indices.size())
780  // Stop searching
781  return success();
782 
783  return TypeSwitch<Type, LogicalResult>(baseGEPType)
784  .Case<LLVMStructType>([&](LLVMStructType structType) -> LogicalResult {
785  auto attr = dyn_cast<IntegerAttr>(indices[indexPos]);
786  if (!attr)
787  return emitOpError() << "expected index " << indexPos
788  << " indexing a struct to be constant";
789 
790  int32_t gepIndex = attr.getInt();
791  ArrayRef<Type> elementTypes = structType.getBody();
792  if (gepIndex < 0 ||
793  static_cast<size_t>(gepIndex) >= elementTypes.size())
794  return emitOpError() << "index " << indexPos
795  << " indexing a struct is out of bounds";
796 
797  // Instead of recursively going into every children types, we only
798  // dive into the one indexed by gepIndex.
799  return verifyStructIndices(elementTypes[gepIndex], indexPos + 1,
800  indices, emitOpError);
801  })
802  .Case<VectorType, LLVMArrayType>(
803  [&](auto containerType) -> LogicalResult {
804  return verifyStructIndices(containerType.getElementType(),
805  indexPos + 1, indices, emitOpError);
806  })
807  .Default([&](auto otherType) -> LogicalResult {
808  return emitOpError()
809  << "type " << otherType << " cannot be indexed (index #"
810  << indexPos << ")";
811  });
812 }
813 
814 /// Driver function around `verifyStructIndices`.
815 static LogicalResult
817  function_ref<InFlightDiagnostic()> emitOpError) {
818  return verifyStructIndices(baseGEPType, /*indexPos=*/1, indices, emitOpError);
819 }
820 
821 LogicalResult LLVM::GEPOp::verify() {
822  if (static_cast<size_t>(
823  llvm::count(getRawConstantIndices(), kDynamicIndex)) !=
824  getDynamicIndices().size())
825  return emitOpError("expected as many dynamic indices as specified in '")
826  << getRawConstantIndicesAttrName().getValue() << "'";
827 
828  if (getNoWrapFlags() == GEPNoWrapFlags::inboundsFlag)
829  return emitOpError("'inbounds_flag' cannot be used directly.");
830 
831  return verifyStructIndices(getElemType(), getIndices(),
832  [&] { return emitOpError(); });
833 }
834 
835 //===----------------------------------------------------------------------===//
836 // LoadOp
837 //===----------------------------------------------------------------------===//
838 
839 void LoadOp::getEffects(
841  &effects) {
842  effects.emplace_back(MemoryEffects::Read::get(), &getAddrMutable());
843  // Volatile operations can have target-specific read-write effects on
844  // memory besides the one referred to by the pointer operand.
845  // Similarly, atomic operations that are monotonic or stricter cause
846  // synchronization that from a language point-of-view, are arbitrary
847  // read-writes into memory.
848  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
849  getOrdering() != AtomicOrdering::unordered)) {
850  effects.emplace_back(MemoryEffects::Write::get());
851  effects.emplace_back(MemoryEffects::Read::get());
852  }
853 }
854 
855 /// Returns true if the given type is supported by atomic operations. All
856 /// integer, float, and pointer types with a power-of-two bitsize and a minimal
857 /// size of 8 bits are supported.
859  const DataLayout &dataLayout) {
860  if (!isa<IntegerType, LLVMPointerType>(type))
862  return false;
863 
864  llvm::TypeSize bitWidth = dataLayout.getTypeSizeInBits(type);
865  if (bitWidth.isScalable())
866  return false;
867  // Needs to be at least 8 bits and a power of two.
868  return bitWidth >= 8 && (bitWidth & (bitWidth - 1)) == 0;
869 }
870 
871 /// Verifies the attributes and the type of atomic memory access operations.
872 template <typename OpTy>
873 static LogicalResult
874 verifyAtomicMemOp(OpTy memOp, Type valueType,
875  ArrayRef<AtomicOrdering> unsupportedOrderings) {
876  if (memOp.getOrdering() != AtomicOrdering::not_atomic) {
877  DataLayout dataLayout = DataLayout::closest(memOp);
878  if (!isTypeCompatibleWithAtomicOp(valueType, dataLayout))
879  return memOp.emitOpError("unsupported type ")
880  << valueType << " for atomic access";
881  if (llvm::is_contained(unsupportedOrderings, memOp.getOrdering()))
882  return memOp.emitOpError("unsupported ordering '")
883  << stringifyAtomicOrdering(memOp.getOrdering()) << "'";
884  if (!memOp.getAlignment())
885  return memOp.emitOpError("expected alignment for atomic access");
886  return success();
887  }
888  if (memOp.getSyncscope())
889  return memOp.emitOpError(
890  "expected syncscope to be null for non-atomic access");
891  return success();
892 }
893 
894 LogicalResult LoadOp::verify() {
895  Type valueType = getResult().getType();
896  return verifyAtomicMemOp(*this, valueType,
897  {AtomicOrdering::release, AtomicOrdering::acq_rel});
898 }
899 
900 void LoadOp::build(OpBuilder &builder, OperationState &state, Type type,
901  Value addr, unsigned alignment, bool isVolatile,
902  bool isNonTemporal, bool isInvariant, bool isInvariantGroup,
903  AtomicOrdering ordering, StringRef syncscope) {
904  build(builder, state, type, addr,
905  alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
906  isNonTemporal, isInvariant, isInvariantGroup, ordering,
907  syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
908  /*dereferenceable=*/nullptr,
909  /*access_groups=*/nullptr,
910  /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
911  /*tbaa=*/nullptr);
912 }
913 
914 //===----------------------------------------------------------------------===//
915 // StoreOp
916 //===----------------------------------------------------------------------===//
917 
918 void StoreOp::getEffects(
920  &effects) {
921  effects.emplace_back(MemoryEffects::Write::get(), &getAddrMutable());
922  // Volatile operations can have target-specific read-write effects on
923  // memory besides the one referred to by the pointer operand.
924  // Similarly, atomic operations that are monotonic or stricter cause
925  // synchronization that from a language point-of-view, are arbitrary
926  // read-writes into memory.
927  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
928  getOrdering() != AtomicOrdering::unordered)) {
929  effects.emplace_back(MemoryEffects::Write::get());
930  effects.emplace_back(MemoryEffects::Read::get());
931  }
932 }
933 
934 LogicalResult StoreOp::verify() {
935  Type valueType = getValue().getType();
936  return verifyAtomicMemOp(*this, valueType,
937  {AtomicOrdering::acquire, AtomicOrdering::acq_rel});
938 }
939 
940 void StoreOp::build(OpBuilder &builder, OperationState &state, Value value,
941  Value addr, unsigned alignment, bool isVolatile,
942  bool isNonTemporal, bool isInvariantGroup,
943  AtomicOrdering ordering, StringRef syncscope) {
944  build(builder, state, value, addr,
945  alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
946  isNonTemporal, isInvariantGroup, ordering,
947  syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
948  /*access_groups=*/nullptr,
949  /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
950 }
951 
952 //===----------------------------------------------------------------------===//
953 // CallOp
954 //===----------------------------------------------------------------------===//
955 
956 /// Gets the MLIR Op-like result types of a LLVMFunctionType.
957 static SmallVector<Type, 1> getCallOpResultTypes(LLVMFunctionType calleeType) {
958  SmallVector<Type, 1> results;
959  Type resultType = calleeType.getReturnType();
960  if (!isa<LLVM::LLVMVoidType>(resultType))
961  results.push_back(resultType);
962  return results;
963 }
964 
965 /// Gets the variadic callee type for a LLVMFunctionType.
966 static TypeAttr getCallOpVarCalleeType(LLVMFunctionType calleeType) {
967  return calleeType.isVarArg() ? TypeAttr::get(calleeType) : nullptr;
968 }
969 
970 /// Constructs a LLVMFunctionType from MLIR `results` and `args`.
971 static LLVMFunctionType getLLVMFuncType(MLIRContext *context, TypeRange results,
972  ValueRange args) {
973  Type resultType;
974  if (results.empty())
975  resultType = LLVMVoidType::get(context);
976  else
977  resultType = results.front();
978  return LLVMFunctionType::get(resultType, llvm::to_vector(args.getTypes()),
979  /*isVarArg=*/false);
980 }
981 
982 void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results,
983  StringRef callee, ValueRange args) {
984  build(builder, state, results, builder.getStringAttr(callee), args);
985 }
986 
987 void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results,
988  StringAttr callee, ValueRange args) {
989  build(builder, state, results, SymbolRefAttr::get(callee), args);
990 }
991 
992 void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results,
993  FlatSymbolRefAttr callee, ValueRange args) {
994  assert(callee && "expected non-null callee in direct call builder");
995  build(builder, state, results,
996  /*var_callee_type=*/nullptr, callee, args, /*fastmathFlags=*/nullptr,
997  /*CConv=*/nullptr, /*TailCallKind=*/nullptr,
998  /*memory_effects=*/nullptr,
999  /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
1000  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
1001  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
1002  /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
1003  /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
1004  /*no_inline=*/nullptr, /*always_inline=*/nullptr,
1005  /*inline_hint=*/nullptr);
1006 }
1007 
1008 void CallOp::build(OpBuilder &builder, OperationState &state,
1009  LLVMFunctionType calleeType, StringRef callee,
1010  ValueRange args) {
1011  build(builder, state, calleeType, builder.getStringAttr(callee), args);
1012 }
1013 
1014 void CallOp::build(OpBuilder &builder, OperationState &state,
1015  LLVMFunctionType calleeType, StringAttr callee,
1016  ValueRange args) {
1017  build(builder, state, calleeType, SymbolRefAttr::get(callee), args);
1018 }
1019 
1020 void CallOp::build(OpBuilder &builder, OperationState &state,
1021  LLVMFunctionType calleeType, FlatSymbolRefAttr callee,
1022  ValueRange args) {
1023  build(builder, state, getCallOpResultTypes(calleeType),
1024  getCallOpVarCalleeType(calleeType), callee, args,
1025  /*fastmathFlags=*/nullptr,
1026  /*CConv=*/nullptr,
1027  /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr,
1028  /*convergent=*/nullptr,
1029  /*no_unwind=*/nullptr, /*will_return=*/nullptr,
1030  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
1031  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
1032  /*access_groups=*/nullptr,
1033  /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
1034  /*no_inline=*/nullptr, /*always_inline=*/nullptr,
1035  /*inline_hint=*/nullptr);
1036 }
1037 
1038 void CallOp::build(OpBuilder &builder, OperationState &state,
1039  LLVMFunctionType calleeType, ValueRange args) {
1040  build(builder, state, getCallOpResultTypes(calleeType),
1041  getCallOpVarCalleeType(calleeType),
1042  /*callee=*/nullptr, args,
1043  /*fastmathFlags=*/nullptr,
1044  /*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr,
1045  /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
1046  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
1047  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
1048  /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
1049  /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
1050  /*no_inline=*/nullptr, /*always_inline=*/nullptr,
1051  /*inline_hint=*/nullptr);
1052 }
1053 
1054 void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func,
1055  ValueRange args) {
1056  auto calleeType = func.getFunctionType();
1057  build(builder, state, getCallOpResultTypes(calleeType),
1058  getCallOpVarCalleeType(calleeType), SymbolRefAttr::get(func), args,
1059  /*fastmathFlags=*/nullptr,
1060  /*CConv=*/nullptr, /*TailCallKind=*/nullptr, /*memory_effects=*/nullptr,
1061  /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
1062  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
1063  /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
1064  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
1065  /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
1066  /*no_inline=*/nullptr, /*always_inline=*/nullptr,
1067  /*inline_hint=*/nullptr);
1068 }
1069 
1070 CallInterfaceCallable CallOp::getCallableForCallee() {
1071  // Direct call.
1072  if (FlatSymbolRefAttr calleeAttr = getCalleeAttr())
1073  return calleeAttr;
1074  // Indirect call, callee Value is the first operand.
1075  return getOperand(0);
1076 }
1077 
1078 void CallOp::setCalleeFromCallable(CallInterfaceCallable callee) {
1079  // Direct call.
1080  if (FlatSymbolRefAttr calleeAttr = getCalleeAttr()) {
1081  auto symRef = cast<SymbolRefAttr>(callee);
1082  return setCalleeAttr(cast<FlatSymbolRefAttr>(symRef));
1083  }
1084  // Indirect call, callee Value is the first operand.
1085  return setOperand(0, cast<Value>(callee));
1086 }
1087 
1088 Operation::operand_range CallOp::getArgOperands() {
1089  return getCalleeOperands().drop_front(getCallee().has_value() ? 0 : 1);
1090 }
1091 
1092 MutableOperandRange CallOp::getArgOperandsMutable() {
1093  return MutableOperandRange(*this, getCallee().has_value() ? 0 : 1,
1094  getCalleeOperands().size());
1095 }
1096 
1097 /// Verify that an inlinable callsite of a debug-info-bearing function in a
1098 /// debug-info-bearing function has a debug location attached to it. This
1099 /// mirrors an LLVM IR verifier.
1100 static LogicalResult verifyCallOpDebugInfo(CallOp callOp, LLVMFuncOp callee) {
1101  if (callee.isExternal())
1102  return success();
1103  auto parentFunc = callOp->getParentOfType<FunctionOpInterface>();
1104  if (!parentFunc)
1105  return success();
1106 
1107  auto hasSubprogram = [](Operation *op) {
1108  return op->getLoc()
1109  ->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>() !=
1110  nullptr;
1111  };
1112  if (!hasSubprogram(parentFunc) || !hasSubprogram(callee))
1113  return success();
1114  bool containsLoc = !isa<UnknownLoc>(callOp->getLoc());
1115  if (!containsLoc)
1116  return callOp.emitError()
1117  << "inlinable function call in a function with a DISubprogram "
1118  "location must have a debug location";
1119  return success();
1120 }
1121 
1122 /// Verify that the parameter and return types of the variadic callee type match
1123 /// the `callOp` argument and result types.
1124 template <typename OpTy>
1125 static LogicalResult verifyCallOpVarCalleeType(OpTy callOp) {
1126  std::optional<LLVMFunctionType> varCalleeType = callOp.getVarCalleeType();
1127  if (!varCalleeType)
1128  return success();
1129 
1130  // Verify the variadic callee type is a variadic function type.
1131  if (!varCalleeType->isVarArg())
1132  return callOp.emitOpError(
1133  "expected var_callee_type to be a variadic function type");
1134 
1135  // Verify the variadic callee type has at most as many parameters as the call
1136  // has argument operands.
1137  if (varCalleeType->getNumParams() > callOp.getArgOperands().size())
1138  return callOp.emitOpError("expected var_callee_type to have at most ")
1139  << callOp.getArgOperands().size() << " parameters";
1140 
1141  // Verify the variadic callee type matches the call argument types.
1142  for (auto [paramType, operand] :
1143  llvm::zip(varCalleeType->getParams(), callOp.getArgOperands()))
1144  if (paramType != operand.getType())
1145  return callOp.emitOpError()
1146  << "var_callee_type parameter type mismatch: " << paramType
1147  << " != " << operand.getType();
1148 
1149  // Verify the variadic callee type matches the call result type.
1150  if (!callOp.getNumResults()) {
1151  if (!isa<LLVMVoidType>(varCalleeType->getReturnType()))
1152  return callOp.emitOpError("expected var_callee_type to return void");
1153  } else {
1154  if (callOp.getResult().getType() != varCalleeType->getReturnType())
1155  return callOp.emitOpError("var_callee_type return type mismatch: ")
1156  << varCalleeType->getReturnType()
1157  << " != " << callOp.getResult().getType();
1158  }
1159  return success();
1160 }
1161 
1162 template <typename OpType>
1163 static LogicalResult verifyOperandBundles(OpType &op) {
1164  OperandRangeRange opBundleOperands = op.getOpBundleOperands();
1165  std::optional<ArrayAttr> opBundleTags = op.getOpBundleTags();
1166 
1167  auto isStringAttr = [](Attribute tagAttr) {
1168  return isa<StringAttr>(tagAttr);
1169  };
1170  if (opBundleTags && !llvm::all_of(*opBundleTags, isStringAttr))
1171  return op.emitError("operand bundle tag must be a StringAttr");
1172 
1173  size_t numOpBundles = opBundleOperands.size();
1174  size_t numOpBundleTags = opBundleTags ? opBundleTags->size() : 0;
1175  if (numOpBundles != numOpBundleTags)
1176  return op.emitError("expected ")
1177  << numOpBundles << " operand bundle tags, but actually got "
1178  << numOpBundleTags;
1179 
1180  return success();
1181 }
1182 
1183 LogicalResult CallOp::verify() { return verifyOperandBundles(*this); }
1184 
1185 LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1186  if (failed(verifyCallOpVarCalleeType(*this)))
1187  return failure();
1188 
1189  // Type for the callee, we'll get it differently depending if it is a direct
1190  // or indirect call.
1191  Type fnType;
1192 
1193  bool isIndirect = false;
1194 
1195  // If this is an indirect call, the callee attribute is missing.
1196  FlatSymbolRefAttr calleeName = getCalleeAttr();
1197  if (!calleeName) {
1198  isIndirect = true;
1199  if (!getNumOperands())
1200  return emitOpError(
1201  "must have either a `callee` attribute or at least an operand");
1202  auto ptrType = llvm::dyn_cast<LLVMPointerType>(getOperand(0).getType());
1203  if (!ptrType)
1204  return emitOpError("indirect call expects a pointer as callee: ")
1205  << getOperand(0).getType();
1206 
1207  return success();
1208  } else {
1209  Operation *callee =
1210  symbolTable.lookupNearestSymbolFrom(*this, calleeName.getAttr());
1211  if (!callee)
1212  return emitOpError()
1213  << "'" << calleeName.getValue()
1214  << "' does not reference a symbol in the current scope";
1215  if (auto fn = dyn_cast<LLVMFuncOp>(callee)) {
1216  if (failed(verifyCallOpDebugInfo(*this, fn)))
1217  return failure();
1218  fnType = fn.getFunctionType();
1219  } else if (auto ifunc = dyn_cast<IFuncOp>(callee)) {
1220  fnType = ifunc.getIFuncType();
1221  } else {
1222  return emitOpError()
1223  << "'" << calleeName.getValue()
1224  << "' does not reference a valid LLVM function or IFunc";
1225  }
1226  }
1227 
1228  LLVMFunctionType funcType = llvm::dyn_cast<LLVMFunctionType>(fnType);
1229  if (!funcType)
1230  return emitOpError("callee does not have a functional type: ") << fnType;
1231 
1232  if (funcType.isVarArg() && !getVarCalleeType())
1233  return emitOpError() << "missing var_callee_type attribute for vararg call";
1234 
1235  // Verify that the operand and result types match the callee.
1236 
1237  if (!funcType.isVarArg() &&
1238  funcType.getNumParams() != (getCalleeOperands().size() - isIndirect))
1239  return emitOpError() << "incorrect number of operands ("
1240  << (getCalleeOperands().size() - isIndirect)
1241  << ") for callee (expecting: "
1242  << funcType.getNumParams() << ")";
1243 
1244  if (funcType.getNumParams() > (getCalleeOperands().size() - isIndirect))
1245  return emitOpError() << "incorrect number of operands ("
1246  << (getCalleeOperands().size() - isIndirect)
1247  << ") for varargs callee (expecting at least: "
1248  << funcType.getNumParams() << ")";
1249 
1250  for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i)
1251  if (getOperand(i + isIndirect).getType() != funcType.getParamType(i))
1252  return emitOpError() << "operand type mismatch for operand " << i << ": "
1253  << getOperand(i + isIndirect).getType()
1254  << " != " << funcType.getParamType(i);
1255 
1256  if (getNumResults() == 0 &&
1257  !llvm::isa<LLVM::LLVMVoidType>(funcType.getReturnType()))
1258  return emitOpError() << "expected function call to produce a value";
1259 
1260  if (getNumResults() != 0 &&
1261  llvm::isa<LLVM::LLVMVoidType>(funcType.getReturnType()))
1262  return emitOpError()
1263  << "calling function with void result must not produce values";
1264 
1265  if (getNumResults() > 1)
1266  return emitOpError()
1267  << "expected LLVM function call to produce 0 or 1 result";
1268 
1269  if (getNumResults() && getResult().getType() != funcType.getReturnType())
1270  return emitOpError() << "result type mismatch: " << getResult().getType()
1271  << " != " << funcType.getReturnType();
1272 
1273  return success();
1274 }
1275 
1276 void CallOp::print(OpAsmPrinter &p) {
1277  auto callee = getCallee();
1278  bool isDirect = callee.has_value();
1279 
1280  p << ' ';
1281 
1282  // Print calling convention.
1283  if (getCConv() != LLVM::CConv::C)
1284  p << stringifyCConv(getCConv()) << ' ';
1285 
1286  if (getTailCallKind() != LLVM::TailCallKind::None)
1287  p << tailcallkind::stringifyTailCallKind(getTailCallKind()) << ' ';
1288 
1289  // Print the direct callee if present as a function attribute, or an indirect
1290  // callee (first operand) otherwise.
1291  if (isDirect)
1292  p.printSymbolName(callee.value());
1293  else
1294  p << getOperand(0);
1295 
1296  auto args = getCalleeOperands().drop_front(isDirect ? 0 : 1);
1297  p << '(' << args << ')';
1298 
1299  // Print the variadic callee type if the call is variadic.
1300  if (std::optional<LLVMFunctionType> varCalleeType = getVarCalleeType())
1301  p << " vararg(" << *varCalleeType << ")";
1302 
1303  if (!getOpBundleOperands().empty()) {
1304  p << " ";
1305  printOpBundles(p, *this, getOpBundleOperands(),
1306  getOpBundleOperands().getTypes(), getOpBundleTags());
1307  }
1308 
1309  p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()),
1310  {getCalleeAttrName(), getTailCallKindAttrName(),
1311  getVarCalleeTypeAttrName(), getCConvAttrName(),
1312  getOperandSegmentSizesAttrName(),
1313  getOpBundleSizesAttrName(),
1314  getOpBundleTagsAttrName(), getArgAttrsAttrName(),
1315  getResAttrsAttrName()});
1316 
1317  p << " : ";
1318  if (!isDirect)
1319  p << getOperand(0).getType() << ", ";
1320 
1321  // Reconstruct the MLIR function type from operand and result types.
1323  p, args.getTypes(), getArgAttrsAttr(),
1324  /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());
1325 }
1326 
1327 /// Parses the type of a call operation and resolves the operands if the parsing
1328 /// succeeds. Returns failure otherwise.
1330  OpAsmParser &parser, OperationState &result, bool isDirect,
1333  SmallVectorImpl<DictionaryAttr> &resultAttrs) {
1334  SMLoc trailingTypesLoc = parser.getCurrentLocation();
1335  SmallVector<Type> types;
1336  if (parser.parseColon())
1337  return failure();
1338  if (!isDirect) {
1339  types.emplace_back();
1340  if (parser.parseType(types.back()))
1341  return failure();
1342  if (parser.parseOptionalComma())
1343  return parser.emitError(
1344  trailingTypesLoc, "expected indirect call to have 2 trailing types");
1345  }
1346  SmallVector<Type> argTypes;
1347  SmallVector<Type> resTypes;
1348  if (call_interface_impl::parseFunctionSignature(parser, argTypes, argAttrs,
1349  resTypes, resultAttrs)) {
1350  if (isDirect)
1351  return parser.emitError(trailingTypesLoc,
1352  "expected direct call to have 1 trailing types");
1353  return parser.emitError(trailingTypesLoc,
1354  "expected trailing function type");
1355  }
1356 
1357  if (resTypes.size() > 1)
1358  return parser.emitError(trailingTypesLoc,
1359  "expected function with 0 or 1 result");
1360  if (resTypes.size() == 1 && llvm::isa<LLVM::LLVMVoidType>(resTypes[0]))
1361  return parser.emitError(trailingTypesLoc,
1362  "expected a non-void result type");
1363 
1364  // The head element of the types list matches the callee type for
1365  // indirect calls, while the types list is emtpy for direct calls.
1366  // Append the function input types to resolve the call operation
1367  // operands.
1368  llvm::append_range(types, argTypes);
1369  if (parser.resolveOperands(operands, types, parser.getNameLoc(),
1370  result.operands))
1371  return failure();
1372  if (!resTypes.empty())
1373  result.addTypes(resTypes);
1374 
1375  return success();
1376 }
1377 
1378 /// Parses an optional function pointer operand before the call argument list
1379 /// for indirect calls, or stops parsing at the function identifier otherwise.
1380 static ParseResult parseOptionalCallFuncPtr(
1381  OpAsmParser &parser,
1383  OpAsmParser::UnresolvedOperand funcPtrOperand;
1384  OptionalParseResult parseResult = parser.parseOptionalOperand(funcPtrOperand);
1385  if (parseResult.has_value()) {
1386  if (failed(*parseResult))
1387  return *parseResult;
1388  operands.push_back(funcPtrOperand);
1389  }
1390  return success();
1391 }
1392 
1393 static ParseResult resolveOpBundleOperands(
1394  OpAsmParser &parser, SMLoc loc, OperationState &state,
1396  ArrayRef<SmallVector<Type>> opBundleOperandTypes,
1397  StringAttr opBundleSizesAttrName) {
1398  unsigned opBundleIndex = 0;
1399  for (const auto &[operands, types] :
1400  llvm::zip_equal(opBundleOperands, opBundleOperandTypes)) {
1401  if (operands.size() != types.size())
1402  return parser.emitError(loc, "expected ")
1403  << operands.size()
1404  << " types for operand bundle operands for operand bundle #"
1405  << opBundleIndex << ", but actually got " << types.size();
1406  if (parser.resolveOperands(operands, types, loc, state.operands))
1407  return failure();
1408  }
1409 
1410  SmallVector<int32_t> opBundleSizes;
1411  opBundleSizes.reserve(opBundleOperands.size());
1412  for (const auto &operands : opBundleOperands)
1413  opBundleSizes.push_back(operands.size());
1414 
1415  state.addAttribute(
1416  opBundleSizesAttrName,
1417  DenseI32ArrayAttr::get(parser.getContext(), opBundleSizes));
1418 
1419  return success();
1420 }
1421 
1422 // <operation> ::= `llvm.call` (cconv)? (tailcallkind)? (function-id | ssa-use)
1423 // `(` ssa-use-list `)`
1424 // ( `vararg(` var-callee-type `)` )?
1425 // ( `[` op-bundles-list `]` )?
1426 // attribute-dict? `:` (type `,`)? function-type
1427 ParseResult CallOp::parse(OpAsmParser &parser, OperationState &result) {
1428  SymbolRefAttr funcAttr;
1429  TypeAttr varCalleeType;
1432  SmallVector<SmallVector<Type>> opBundleOperandTypes;
1433  ArrayAttr opBundleTags;
1434 
1435  // Default to C Calling Convention if no keyword is provided.
1436  result.addAttribute(
1437  getCConvAttrName(result.name),
1438  CConvAttr::get(parser.getContext(),
1439  parseOptionalLLVMKeyword<CConv>(parser, LLVM::CConv::C)));
1440 
1441  result.addAttribute(
1442  getTailCallKindAttrName(result.name),
1444  parseOptionalLLVMKeyword<TailCallKind>(
1445  parser, LLVM::TailCallKind::None)));
1446 
1447  // Parse a function pointer for indirect calls.
1448  if (parseOptionalCallFuncPtr(parser, operands))
1449  return failure();
1450  bool isDirect = operands.empty();
1451 
1452  // Parse a function identifier for direct calls.
1453  if (isDirect)
1454  if (parser.parseAttribute(funcAttr, "callee", result.attributes))
1455  return failure();
1456 
1457  // Parse the function arguments.
1458  if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren))
1459  return failure();
1460 
1461  bool isVarArg = parser.parseOptionalKeyword("vararg").succeeded();
1462  if (isVarArg) {
1463  StringAttr varCalleeTypeAttrName =
1464  CallOp::getVarCalleeTypeAttrName(result.name);
1465  if (parser.parseLParen().failed() ||
1466  parser
1467  .parseAttribute(varCalleeType, varCalleeTypeAttrName,
1468  result.attributes)
1469  .failed() ||
1470  parser.parseRParen().failed())
1471  return failure();
1472  }
1473 
1474  SMLoc opBundlesLoc = parser.getCurrentLocation();
1475  if (std::optional<ParseResult> result = parseOpBundles(
1476  parser, opBundleOperands, opBundleOperandTypes, opBundleTags);
1477  result && failed(*result))
1478  return failure();
1479  if (opBundleTags && !opBundleTags.empty())
1480  result.addAttribute(CallOp::getOpBundleTagsAttrName(result.name).getValue(),
1481  opBundleTags);
1482 
1483  if (parser.parseOptionalAttrDict(result.attributes))
1484  return failure();
1485 
1486  // Parse the trailing type list and resolve the operands.
1487  SmallVector<DictionaryAttr> argAttrs;
1488  SmallVector<DictionaryAttr> resultAttrs;
1489  if (parseCallTypeAndResolveOperands(parser, result, isDirect, operands,
1490  argAttrs, resultAttrs))
1491  return failure();
1493  parser.getBuilder(), result, argAttrs, resultAttrs,
1494  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
1495  if (resolveOpBundleOperands(parser, opBundlesLoc, result, opBundleOperands,
1496  opBundleOperandTypes,
1497  getOpBundleSizesAttrName(result.name)))
1498  return failure();
1499 
1500  int32_t numOpBundleOperands = 0;
1501  for (const auto &operands : opBundleOperands)
1502  numOpBundleOperands += operands.size();
1503 
1504  result.addAttribute(
1505  CallOp::getOperandSegmentSizeAttr(),
1507  {static_cast<int32_t>(operands.size()), numOpBundleOperands}));
1508  return success();
1509 }
1510 
1511 LLVMFunctionType CallOp::getCalleeFunctionType() {
1512  if (std::optional<LLVMFunctionType> varCalleeType = getVarCalleeType())
1513  return *varCalleeType;
1514  return getLLVMFuncType(getContext(), getResultTypes(), getArgOperands());
1515 }
1516 
1517 ///===---------------------------------------------------------------------===//
1518 /// LLVM::InvokeOp
1519 ///===---------------------------------------------------------------------===//
1520 
1521 void InvokeOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func,
1522  ValueRange ops, Block *normal, ValueRange normalOps,
1523  Block *unwind, ValueRange unwindOps) {
1524  auto calleeType = func.getFunctionType();
1525  build(builder, state, getCallOpResultTypes(calleeType),
1526  getCallOpVarCalleeType(calleeType), SymbolRefAttr::get(func), ops,
1527  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, normalOps, unwindOps,
1528  nullptr, nullptr, {}, {}, normal, unwind);
1529 }
1530 
1531 void InvokeOp::build(OpBuilder &builder, OperationState &state, TypeRange tys,
1532  FlatSymbolRefAttr callee, ValueRange ops, Block *normal,
1533  ValueRange normalOps, Block *unwind,
1534  ValueRange unwindOps) {
1535  build(builder, state, tys,
1536  /*var_callee_type=*/nullptr, callee, ops, /*arg_attrs=*/nullptr,
1537  /*res_attrs=*/nullptr, normalOps, unwindOps, nullptr, nullptr, {}, {},
1538  normal, unwind);
1539 }
1540 
1541 void InvokeOp::build(OpBuilder &builder, OperationState &state,
1542  LLVMFunctionType calleeType, FlatSymbolRefAttr callee,
1543  ValueRange ops, Block *normal, ValueRange normalOps,
1544  Block *unwind, ValueRange unwindOps) {
1545  build(builder, state, getCallOpResultTypes(calleeType),
1546  getCallOpVarCalleeType(calleeType), callee, ops,
1547  /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, normalOps, unwindOps,
1548  nullptr, nullptr, {}, {}, normal, unwind);
1549 }
1550 
1552  assert(index < getNumSuccessors() && "invalid successor index");
1553  return SuccessorOperands(index == 0 ? getNormalDestOperandsMutable()
1554  : getUnwindDestOperandsMutable());
1555 }
1556 
1557 CallInterfaceCallable InvokeOp::getCallableForCallee() {
1558  // Direct call.
1559  if (FlatSymbolRefAttr calleeAttr = getCalleeAttr())
1560  return calleeAttr;
1561  // Indirect call, callee Value is the first operand.
1562  return getOperand(0);
1563 }
1564 
1565 void InvokeOp::setCalleeFromCallable(CallInterfaceCallable callee) {
1566  // Direct call.
1567  if (FlatSymbolRefAttr calleeAttr = getCalleeAttr()) {
1568  auto symRef = cast<SymbolRefAttr>(callee);
1569  return setCalleeAttr(cast<FlatSymbolRefAttr>(symRef));
1570  }
1571  // Indirect call, callee Value is the first operand.
1572  return setOperand(0, cast<Value>(callee));
1573 }
1574 
1575 Operation::operand_range InvokeOp::getArgOperands() {
1576  return getCalleeOperands().drop_front(getCallee().has_value() ? 0 : 1);
1577 }
1578 
1579 MutableOperandRange InvokeOp::getArgOperandsMutable() {
1580  return MutableOperandRange(*this, getCallee().has_value() ? 0 : 1,
1581  getCalleeOperands().size());
1582 }
1583 
1584 LogicalResult InvokeOp::verify() {
1585  if (failed(verifyCallOpVarCalleeType(*this)))
1586  return failure();
1587 
1588  Block *unwindDest = getUnwindDest();
1589  if (unwindDest->empty())
1590  return emitError("must have at least one operation in unwind destination");
1591 
1592  // In unwind destination, first operation must be LandingpadOp
1593  if (!isa<LandingpadOp>(unwindDest->front()))
1594  return emitError("first operation in unwind destination should be a "
1595  "llvm.landingpad operation");
1596 
1597  if (failed(verifyOperandBundles(*this)))
1598  return failure();
1599 
1600  return success();
1601 }
1602 
1603 void InvokeOp::print(OpAsmPrinter &p) {
1604  auto callee = getCallee();
1605  bool isDirect = callee.has_value();
1606 
1607  p << ' ';
1608 
1609  // Print calling convention.
1610  if (getCConv() != LLVM::CConv::C)
1611  p << stringifyCConv(getCConv()) << ' ';
1612 
1613  // Either function name or pointer
1614  if (isDirect)
1615  p.printSymbolName(callee.value());
1616  else
1617  p << getOperand(0);
1618 
1619  p << '(' << getCalleeOperands().drop_front(isDirect ? 0 : 1) << ')';
1620  p << " to ";
1621  p.printSuccessorAndUseList(getNormalDest(), getNormalDestOperands());
1622  p << " unwind ";
1623  p.printSuccessorAndUseList(getUnwindDest(), getUnwindDestOperands());
1624 
1625  // Print the variadic callee type if the invoke is variadic.
1626  if (std::optional<LLVMFunctionType> varCalleeType = getVarCalleeType())
1627  p << " vararg(" << *varCalleeType << ")";
1628 
1629  if (!getOpBundleOperands().empty()) {
1630  p << " ";
1631  printOpBundles(p, *this, getOpBundleOperands(),
1632  getOpBundleOperands().getTypes(), getOpBundleTags());
1633  }
1634 
1635  p.printOptionalAttrDict((*this)->getAttrs(),
1636  {getCalleeAttrName(), getOperandSegmentSizeAttr(),
1637  getCConvAttrName(), getVarCalleeTypeAttrName(),
1638  getOpBundleSizesAttrName(),
1639  getOpBundleTagsAttrName(), getArgAttrsAttrName(),
1640  getResAttrsAttrName()});
1641 
1642  p << " : ";
1643  if (!isDirect)
1644  p << getOperand(0).getType() << ", ";
1646  p, getCalleeOperands().drop_front(isDirect ? 0 : 1).getTypes(),
1647  getArgAttrsAttr(),
1648  /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());
1649 }
1650 
1651 // <operation> ::= `llvm.invoke` (cconv)? (function-id | ssa-use)
1652 // `(` ssa-use-list `)`
1653 // `to` bb-id (`[` ssa-use-and-type-list `]`)?
1654 // `unwind` bb-id (`[` ssa-use-and-type-list `]`)?
1655 // ( `vararg(` var-callee-type `)` )?
1656 // ( `[` op-bundles-list `]` )?
1657 // attribute-dict? `:` (type `,`)?
1658 // function-type-with-argument-attributes
1659 ParseResult InvokeOp::parse(OpAsmParser &parser, OperationState &result) {
1661  SymbolRefAttr funcAttr;
1662  TypeAttr varCalleeType;
1664  SmallVector<SmallVector<Type>> opBundleOperandTypes;
1665  ArrayAttr opBundleTags;
1666  Block *normalDest, *unwindDest;
1667  SmallVector<Value, 4> normalOperands, unwindOperands;
1668  Builder &builder = parser.getBuilder();
1669 
1670  // Default to C Calling Convention if no keyword is provided.
1671  result.addAttribute(
1672  getCConvAttrName(result.name),
1673  CConvAttr::get(parser.getContext(),
1674  parseOptionalLLVMKeyword<CConv>(parser, LLVM::CConv::C)));
1675 
1676  // Parse a function pointer for indirect calls.
1677  if (parseOptionalCallFuncPtr(parser, operands))
1678  return failure();
1679  bool isDirect = operands.empty();
1680 
1681  // Parse a function identifier for direct calls.
1682  if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes))
1683  return failure();
1684 
1685  // Parse the function arguments.
1686  if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) ||
1687  parser.parseKeyword("to") ||
1688  parser.parseSuccessorAndUseList(normalDest, normalOperands) ||
1689  parser.parseKeyword("unwind") ||
1690  parser.parseSuccessorAndUseList(unwindDest, unwindOperands))
1691  return failure();
1692 
1693  bool isVarArg = parser.parseOptionalKeyword("vararg").succeeded();
1694  if (isVarArg) {
1695  StringAttr varCalleeTypeAttrName =
1696  InvokeOp::getVarCalleeTypeAttrName(result.name);
1697  if (parser.parseLParen().failed() ||
1698  parser
1699  .parseAttribute(varCalleeType, varCalleeTypeAttrName,
1700  result.attributes)
1701  .failed() ||
1702  parser.parseRParen().failed())
1703  return failure();
1704  }
1705 
1706  SMLoc opBundlesLoc = parser.getCurrentLocation();
1707  if (std::optional<ParseResult> result = parseOpBundles(
1708  parser, opBundleOperands, opBundleOperandTypes, opBundleTags);
1709  result && failed(*result))
1710  return failure();
1711  if (opBundleTags && !opBundleTags.empty())
1712  result.addAttribute(
1713  InvokeOp::getOpBundleTagsAttrName(result.name).getValue(),
1714  opBundleTags);
1715 
1716  if (parser.parseOptionalAttrDict(result.attributes))
1717  return failure();
1718 
1719  // Parse the trailing type list and resolve the function operands.
1720  SmallVector<DictionaryAttr> argAttrs;
1721  SmallVector<DictionaryAttr> resultAttrs;
1722  if (parseCallTypeAndResolveOperands(parser, result, isDirect, operands,
1723  argAttrs, resultAttrs))
1724  return failure();
1726  parser.getBuilder(), result, argAttrs, resultAttrs,
1727  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
1728 
1729  if (resolveOpBundleOperands(parser, opBundlesLoc, result, opBundleOperands,
1730  opBundleOperandTypes,
1731  getOpBundleSizesAttrName(result.name)))
1732  return failure();
1733 
1734  result.addSuccessors({normalDest, unwindDest});
1735  result.addOperands(normalOperands);
1736  result.addOperands(unwindOperands);
1737 
1738  int32_t numOpBundleOperands = 0;
1739  for (const auto &operands : opBundleOperands)
1740  numOpBundleOperands += operands.size();
1741 
1742  result.addAttribute(
1743  InvokeOp::getOperandSegmentSizeAttr(),
1744  builder.getDenseI32ArrayAttr({static_cast<int32_t>(operands.size()),
1745  static_cast<int32_t>(normalOperands.size()),
1746  static_cast<int32_t>(unwindOperands.size()),
1747  numOpBundleOperands}));
1748  return success();
1749 }
1750 
1751 LLVMFunctionType InvokeOp::getCalleeFunctionType() {
1752  if (std::optional<LLVMFunctionType> varCalleeType = getVarCalleeType())
1753  return *varCalleeType;
1754  return getLLVMFuncType(getContext(), getResultTypes(), getArgOperands());
1755 }
1756 
1757 ///===----------------------------------------------------------------------===//
1758 /// Verifying/Printing/Parsing for LLVM::LandingpadOp.
1759 ///===----------------------------------------------------------------------===//
1760 
1761 LogicalResult LandingpadOp::verify() {
1762  Value value;
1763  if (LLVMFuncOp func = (*this)->getParentOfType<LLVMFuncOp>()) {
1764  if (!func.getPersonality())
1765  return emitError(
1766  "llvm.landingpad needs to be in a function with a personality");
1767  }
1768 
1769  // Consistency of llvm.landingpad result types is checked in
1770  // LLVMFuncOp::verify().
1771 
1772  if (!getCleanup() && getOperands().empty())
1773  return emitError("landingpad instruction expects at least one clause or "
1774  "cleanup attribute");
1775 
1776  for (unsigned idx = 0, ie = getNumOperands(); idx < ie; idx++) {
1777  value = getOperand(idx);
1778  bool isFilter = llvm::isa<LLVMArrayType>(value.getType());
1779  if (isFilter) {
1780  // FIXME: Verify filter clauses when arrays are appropriately handled
1781  } else {
1782  // catch - global addresses only.
1783  // Bitcast ops should have global addresses as their args.
1784  if (auto bcOp = value.getDefiningOp<BitcastOp>()) {
1785  if (auto addrOp = bcOp.getArg().getDefiningOp<AddressOfOp>())
1786  continue;
1787  return emitError("constant clauses expected").attachNote(bcOp.getLoc())
1788  << "global addresses expected as operand to "
1789  "bitcast used in clauses for landingpad";
1790  }
1791  // ZeroOp and AddressOfOp allowed
1792  if (value.getDefiningOp<ZeroOp>())
1793  continue;
1794  if (value.getDefiningOp<AddressOfOp>())
1795  continue;
1796  return emitError("clause #")
1797  << idx << " is not a known constant - null, addressof, bitcast";
1798  }
1799  }
1800  return success();
1801 }
1802 
1804  p << (getCleanup() ? " cleanup " : " ");
1805 
1806  // Clauses
1807  for (auto value : getOperands()) {
1808  // Similar to llvm - if clause is an array type then it is filter
1809  // clause else catch clause
1810  bool isArrayTy = llvm::isa<LLVMArrayType>(value.getType());
1811  p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : "
1812  << value.getType() << ") ";
1813  }
1814 
1815  p.printOptionalAttrDict((*this)->getAttrs(), {"cleanup"});
1816 
1817  p << ": " << getType();
1818 }
1819 
1820 // <operation> ::= `llvm.landingpad` `cleanup`?
1821 // ((`catch` | `filter`) operand-type ssa-use)* attribute-dict?
1822 ParseResult LandingpadOp::parse(OpAsmParser &parser, OperationState &result) {
1823  // Check for cleanup
1824  if (succeeded(parser.parseOptionalKeyword("cleanup")))
1825  result.addAttribute("cleanup", parser.getBuilder().getUnitAttr());
1826 
1827  // Parse clauses with types
1828  while (succeeded(parser.parseOptionalLParen()) &&
1829  (succeeded(parser.parseOptionalKeyword("filter")) ||
1830  succeeded(parser.parseOptionalKeyword("catch")))) {
1832  Type ty;
1833  if (parser.parseOperand(operand) || parser.parseColon() ||
1834  parser.parseType(ty) ||
1835  parser.resolveOperand(operand, ty, result.operands) ||
1836  parser.parseRParen())
1837  return failure();
1838  }
1839 
1840  Type type;
1841  if (parser.parseColon() || parser.parseType(type))
1842  return failure();
1843 
1844  result.addTypes(type);
1845  return success();
1846 }
1847 
1848 //===----------------------------------------------------------------------===//
1849 // ExtractValueOp
1850 //===----------------------------------------------------------------------===//
1851 
1852 /// Extract the type at `position` in the LLVM IR aggregate type
1853 /// `containerType`. Each element of `position` is an index into a nested
1854 /// aggregate type. Return the resulting type or emit an error.
1856  function_ref<InFlightDiagnostic(StringRef)> emitError, Type containerType,
1857  ArrayRef<int64_t> position) {
1858  Type llvmType = containerType;
1859  if (!isCompatibleType(containerType)) {
1860  emitError("expected LLVM IR Dialect type, got ") << containerType;
1861  return {};
1862  }
1863 
1864  // Infer the element type from the structure type: iteratively step inside the
1865  // type by taking the element type, indexed by the position attribute for
1866  // structures. Check the position index before accessing, it is supposed to
1867  // be in bounds.
1868  for (int64_t idx : position) {
1869  if (auto arrayType = llvm::dyn_cast<LLVMArrayType>(llvmType)) {
1870  if (idx < 0 || static_cast<unsigned>(idx) >= arrayType.getNumElements()) {
1871  emitError("position out of bounds: ") << idx;
1872  return {};
1873  }
1874  llvmType = arrayType.getElementType();
1875  } else if (auto structType = llvm::dyn_cast<LLVMStructType>(llvmType)) {
1876  if (idx < 0 ||
1877  static_cast<unsigned>(idx) >= structType.getBody().size()) {
1878  emitError("position out of bounds: ") << idx;
1879  return {};
1880  }
1881  llvmType = structType.getBody()[idx];
1882  } else {
1883  emitError("expected LLVM IR structure/array type, got: ") << llvmType;
1884  return {};
1885  }
1886  }
1887  return llvmType;
1888 }
1889 
1890 /// Extract the type at `position` in the wrapped LLVM IR aggregate type
1891 /// `containerType`.
1893  ArrayRef<int64_t> position) {
1894  for (int64_t idx : position) {
1895  if (auto structType = llvm::dyn_cast<LLVMStructType>(llvmType))
1896  llvmType = structType.getBody()[idx];
1897  else
1898  llvmType = llvm::cast<LLVMArrayType>(llvmType).getElementType();
1899  }
1900  return llvmType;
1901 }
1902 
1903 OpFoldResult LLVM::ExtractValueOp::fold(FoldAdaptor adaptor) {
1904  if (auto extractValueOp = getContainer().getDefiningOp<ExtractValueOp>()) {
1905  SmallVector<int64_t, 4> newPos(extractValueOp.getPosition());
1906  newPos.append(getPosition().begin(), getPosition().end());
1907  setPosition(newPos);
1908  getContainerMutable().set(extractValueOp.getContainer());
1909  return getResult();
1910  }
1911 
1912  {
1913  DenseElementsAttr constval;
1914  matchPattern(getContainer(), m_Constant(&constval));
1915  if (constval && constval.getElementType() == getType()) {
1916  if (isa<SplatElementsAttr>(constval))
1917  return constval.getSplatValue<Attribute>();
1918  if (getPosition().size() == 1)
1919  return constval.getValues<Attribute>()[getPosition()[0]];
1920  }
1921  }
1922 
1923  auto insertValueOp = getContainer().getDefiningOp<InsertValueOp>();
1924  OpFoldResult result = {};
1925  ArrayRef<int64_t> extractPos = getPosition();
1926  bool switchedToInsertedValue = false;
1927  while (insertValueOp) {
1928  ArrayRef<int64_t> insertPos = insertValueOp.getPosition();
1929  auto extractPosSize = extractPos.size();
1930  auto insertPosSize = insertPos.size();
1931 
1932  // Case 1: Exact match of positions.
1933  if (extractPos == insertPos)
1934  return insertValueOp.getValue();
1935 
1936  // Case 2: Insert position is a prefix of extract position. Continue
1937  // traversal with the inserted value. Example:
1938  // ```
1939  // %0 = llvm.insertvalue %arg1, %undef[0] : !llvm.struct<(i32, i32, i32)>
1940  // %1 = llvm.insertvalue %arg2, %0[1] : !llvm.struct<(i32, i32, i32)>
1941  // %2 = llvm.insertvalue %arg3, %1[2] : !llvm.struct<(i32, i32, i32)>
1942  // %3 = llvm.insertvalue %2, %foo[0]
1943  // : !llvm.struct<(struct<(i32, i32, i32)>, i64)>
1944  // %4 = llvm.extractvalue %3[0, 0]
1945  // : !llvm.struct<(struct<(i32, i32, i32)>, i64)>
1946  // ```
1947  // In the above example, %4 is folded to %arg1.
1948  if (extractPosSize > insertPosSize &&
1949  extractPos.take_front(insertPosSize) == insertPos) {
1950  insertValueOp = insertValueOp.getValue().getDefiningOp<InsertValueOp>();
1951  extractPos = extractPos.drop_front(insertPosSize);
1952  switchedToInsertedValue = true;
1953  continue;
1954  }
1955 
1956  // Case 3: Try to continue the traversal with the container value.
1957  unsigned min = std::min(extractPosSize, insertPosSize);
1958 
1959  // If one is fully prefix of the other, stop propagating back as it will
1960  // miss dependencies. For instance, %3 should not fold to %f0 in the
1961  // following example:
1962  // ```
1963  // %1 = llvm.insertvalue %f0, %0[0, 0] :
1964  // !llvm.array<4 x !llvm.array<4 x f32>>
1965  // %2 = llvm.insertvalue %arr, %1[0] :
1966  // !llvm.array<4 x !llvm.array<4 x f32>>
1967  // %3 = llvm.extractvalue %2[0, 0] : !llvm.array<4 x !llvm.array<4 x f32>>
1968  // ```
1969  if (extractPos.take_front(min) == insertPos.take_front(min))
1970  return result;
1971  // If neither a prefix, nor the exact position, we can extract out of the
1972  // value being inserted into. Moreover, we can try again if that operand
1973  // is itself an insertvalue expression.
1974  if (!switchedToInsertedValue) {
1975  // Do not swap out the container operand if we decided earlier to
1976  // continue the traversal with the inserted value (Case 2).
1977  getContainerMutable().assign(insertValueOp.getContainer());
1978  result = getResult();
1979  }
1980  insertValueOp = insertValueOp.getContainer().getDefiningOp<InsertValueOp>();
1981  }
1982  return result;
1983 }
1984 
1985 LogicalResult ExtractValueOp::verify() {
1986  auto emitError = [this](StringRef msg) { return emitOpError(msg); };
1988  emitError, getContainer().getType(), getPosition());
1989  if (!valueType)
1990  return failure();
1991 
1992  if (getRes().getType() != valueType)
1993  return emitOpError() << "Type mismatch: extracting from "
1994  << getContainer().getType() << " should produce "
1995  << valueType << " but this op returns "
1996  << getRes().getType();
1997  return success();
1998 }
1999 
2000 void ExtractValueOp::build(OpBuilder &builder, OperationState &state,
2001  Value container, ArrayRef<int64_t> position) {
2002  build(builder, state,
2003  getInsertExtractValueElementType(container.getType(), position),
2004  container, builder.getAttr<DenseI64ArrayAttr>(position));
2005 }
2006 
2007 //===----------------------------------------------------------------------===//
2008 // InsertValueOp
2009 //===----------------------------------------------------------------------===//
2010 
2011 /// Infer the value type from the container type and position.
2012 static ParseResult
2014  Type containerType,
2015  DenseI64ArrayAttr position) {
2017  [&](StringRef msg) {
2018  return parser.emitError(parser.getCurrentLocation(), msg);
2019  },
2020  containerType, position.asArrayRef());
2021  return success(!!valueType);
2022 }
2023 
2024 /// Nothing to print for an inferred type.
2026  Operation *op, Type valueType,
2027  Type containerType,
2028  DenseI64ArrayAttr position) {}
2029 
2030 LogicalResult InsertValueOp::verify() {
2031  auto emitError = [this](StringRef msg) { return emitOpError(msg); };
2033  emitError, getContainer().getType(), getPosition());
2034  if (!valueType)
2035  return failure();
2036 
2037  if (getValue().getType() != valueType)
2038  return emitOpError() << "Type mismatch: cannot insert "
2039  << getValue().getType() << " into "
2040  << getContainer().getType();
2041 
2042  return success();
2043 }
2044 
2045 //===----------------------------------------------------------------------===//
2046 // ReturnOp
2047 //===----------------------------------------------------------------------===//
2048 
2049 LogicalResult ReturnOp::verify() {
2050  auto parent = (*this)->getParentOfType<LLVMFuncOp>();
2051  if (!parent)
2052  return success();
2053 
2054  Type expectedType = parent.getFunctionType().getReturnType();
2055  if (llvm::isa<LLVMVoidType>(expectedType)) {
2056  if (!getArg())
2057  return success();
2058  InFlightDiagnostic diag = emitOpError("expected no operands");
2059  diag.attachNote(parent->getLoc()) << "when returning from function";
2060  return diag;
2061  }
2062  if (!getArg()) {
2063  if (llvm::isa<LLVMVoidType>(expectedType))
2064  return success();
2065  InFlightDiagnostic diag = emitOpError("expected 1 operand");
2066  diag.attachNote(parent->getLoc()) << "when returning from function";
2067  return diag;
2068  }
2069  if (expectedType != getArg().getType()) {
2070  InFlightDiagnostic diag = emitOpError("mismatching result types");
2071  diag.attachNote(parent->getLoc()) << "when returning from function";
2072  return diag;
2073  }
2074  return success();
2075 }
2076 
2077 //===----------------------------------------------------------------------===//
2078 // LLVM::AddressOfOp.
2079 //===----------------------------------------------------------------------===//
2080 
2081 GlobalOp AddressOfOp::getGlobal(SymbolTableCollection &symbolTable) {
2082  return dyn_cast_or_null<GlobalOp>(
2083  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
2084 }
2085 
2086 LLVMFuncOp AddressOfOp::getFunction(SymbolTableCollection &symbolTable) {
2087  return dyn_cast_or_null<LLVMFuncOp>(
2088  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
2089 }
2090 
2091 AliasOp AddressOfOp::getAlias(SymbolTableCollection &symbolTable) {
2092  return dyn_cast_or_null<AliasOp>(
2093  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
2094 }
2095 
2096 IFuncOp AddressOfOp::getIFunc(SymbolTableCollection &symbolTable) {
2097  return dyn_cast_or_null<IFuncOp>(
2098  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
2099 }
2100 
2101 LogicalResult
2102 AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2103  Operation *symbol =
2104  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr());
2105 
2106  auto global = dyn_cast_or_null<GlobalOp>(symbol);
2107  auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
2108  auto alias = dyn_cast_or_null<AliasOp>(symbol);
2109  auto ifunc = dyn_cast_or_null<IFuncOp>(symbol);
2110 
2111  if (!global && !function && !alias && !ifunc)
2112  return emitOpError("must reference a global defined by 'llvm.mlir.global', "
2113  "'llvm.mlir.alias' or 'llvm.func' or 'llvm.mlir.ifunc'");
2114 
2115  LLVMPointerType type = getType();
2116  if ((global && global.getAddrSpace() != type.getAddressSpace()) ||
2117  (alias && alias.getAddrSpace() != type.getAddressSpace()))
2118  return emitOpError("pointer address space must match address space of the "
2119  "referenced global or alias");
2120 
2121  return success();
2122 }
2123 
2124 // AddressOfOp constant-folds to the global symbol name.
2125 OpFoldResult LLVM::AddressOfOp::fold(FoldAdaptor) {
2126  return getGlobalNameAttr();
2127 }
2128 
2129 //===----------------------------------------------------------------------===//
2130 // LLVM::DSOLocalEquivalentOp
2131 //===----------------------------------------------------------------------===//
2132 
2133 LLVMFuncOp
2134 DSOLocalEquivalentOp::getFunction(SymbolTableCollection &symbolTable) {
2135  return dyn_cast_or_null<LLVMFuncOp>(symbolTable.lookupSymbolIn(
2136  parentLLVMModule(*this), getFunctionNameAttr()));
2137 }
2138 
2139 AliasOp DSOLocalEquivalentOp::getAlias(SymbolTableCollection &symbolTable) {
2140  return dyn_cast_or_null<AliasOp>(symbolTable.lookupSymbolIn(
2141  parentLLVMModule(*this), getFunctionNameAttr()));
2142 }
2143 
2144 LogicalResult
2145 DSOLocalEquivalentOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2146  Operation *symbol = symbolTable.lookupSymbolIn(parentLLVMModule(*this),
2147  getFunctionNameAttr());
2148  auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
2149  auto alias = dyn_cast_or_null<AliasOp>(symbol);
2150 
2151  if (!function && !alias)
2152  return emitOpError(
2153  "must reference a global defined by 'llvm.func' or 'llvm.mlir.alias'");
2154 
2155  if (alias) {
2156  if (alias.getInitializer()
2157  .walk([&](AddressOfOp addrOp) {
2158  if (addrOp.getGlobal(symbolTable))
2159  return WalkResult::interrupt();
2160  return WalkResult::advance();
2161  })
2162  .wasInterrupted())
2163  return emitOpError("must reference an alias to a function");
2164  }
2165 
2166  if ((function && function.getLinkage() == LLVM::Linkage::ExternWeak) ||
2167  (alias && alias.getLinkage() == LLVM::Linkage::ExternWeak))
2168  return emitOpError(
2169  "target function with 'extern_weak' linkage not allowed");
2170 
2171  return success();
2172 }
2173 
2174 /// Fold a dso_local_equivalent operation to a dedicated dso_local_equivalent
2175 /// attribute.
2176 OpFoldResult DSOLocalEquivalentOp::fold(FoldAdaptor) {
2177  return DSOLocalEquivalentAttr::get(getContext(), getFunctionNameAttr());
2178 }
2179 
2180 //===----------------------------------------------------------------------===//
2181 // Verifier for LLVM::ComdatOp.
2182 //===----------------------------------------------------------------------===//
2183 
2184 void ComdatOp::build(OpBuilder &builder, OperationState &result,
2185  StringRef symName) {
2186  result.addAttribute(getSymNameAttrName(result.name),
2187  builder.getStringAttr(symName));
2188  Region *body = result.addRegion();
2189  body->emplaceBlock();
2190 }
2191 
2192 LogicalResult ComdatOp::verifyRegions() {
2193  Region &body = getBody();
2194  for (Operation &op : body.getOps())
2195  if (!isa<ComdatSelectorOp>(op))
2196  return op.emitError(
2197  "only comdat selector symbols can appear in a comdat region");
2198 
2199  return success();
2200 }
2201 
2202 //===----------------------------------------------------------------------===//
2203 // Builder, printer and verifier for LLVM::GlobalOp.
2204 //===----------------------------------------------------------------------===//
2205 
2206 void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
2207  bool isConstant, Linkage linkage, StringRef name,
2208  Attribute value, uint64_t alignment, unsigned addrSpace,
2209  bool dsoLocal, bool threadLocal, SymbolRefAttr comdat,
2211  ArrayRef<Attribute> dbgExprs) {
2212  result.addAttribute(getSymNameAttrName(result.name),
2213  builder.getStringAttr(name));
2214  result.addAttribute(getGlobalTypeAttrName(result.name), TypeAttr::get(type));
2215  if (isConstant)
2216  result.addAttribute(getConstantAttrName(result.name),
2217  builder.getUnitAttr());
2218  if (value)
2219  result.addAttribute(getValueAttrName(result.name), value);
2220  if (dsoLocal)
2221  result.addAttribute(getDsoLocalAttrName(result.name),
2222  builder.getUnitAttr());
2223  if (threadLocal)
2224  result.addAttribute(getThreadLocal_AttrName(result.name),
2225  builder.getUnitAttr());
2226  if (comdat)
2227  result.addAttribute(getComdatAttrName(result.name), comdat);
2228 
2229  // Only add an alignment attribute if the "alignment" input
2230  // is different from 0. The value must also be a power of two, but
2231  // this is tested in GlobalOp::verify, not here.
2232  if (alignment != 0)
2233  result.addAttribute(getAlignmentAttrName(result.name),
2234  builder.getI64IntegerAttr(alignment));
2235 
2236  result.addAttribute(getLinkageAttrName(result.name),
2237  LinkageAttr::get(builder.getContext(), linkage));
2238  if (addrSpace != 0)
2239  result.addAttribute(getAddrSpaceAttrName(result.name),
2240  builder.getI32IntegerAttr(addrSpace));
2241  result.attributes.append(attrs.begin(), attrs.end());
2242 
2243  if (!dbgExprs.empty())
2244  result.addAttribute(getDbgExprsAttrName(result.name),
2245  ArrayAttr::get(builder.getContext(), dbgExprs));
2246 
2247  result.addRegion();
2248 }
2249 
2250 template <typename OpType>
2251 static void printCommonGlobalAndAlias(OpAsmPrinter &p, OpType op) {
2252  p << ' ' << stringifyLinkage(op.getLinkage()) << ' ';
2253  StringRef visibility = stringifyVisibility(op.getVisibility_());
2254  if (!visibility.empty())
2255  p << visibility << ' ';
2256  if (op.getThreadLocal_())
2257  p << "thread_local ";
2258  if (auto unnamedAddr = op.getUnnamedAddr()) {
2259  StringRef str = stringifyUnnamedAddr(*unnamedAddr);
2260  if (!str.empty())
2261  p << str << ' ';
2262  }
2263 }
2264 
2265 void GlobalOp::print(OpAsmPrinter &p) {
2266  printCommonGlobalAndAlias<GlobalOp>(p, *this);
2267  if (getConstant())
2268  p << "constant ";
2269  p.printSymbolName(getSymName());
2270  p << '(';
2271  if (auto value = getValueOrNull())
2272  p.printAttribute(value);
2273  p << ')';
2274  if (auto comdat = getComdat())
2275  p << " comdat(" << *comdat << ')';
2276 
2277  // Note that the alignment attribute is printed using the
2278  // default syntax here, even though it is an inherent attribute
2279  // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes)
2280  p.printOptionalAttrDict((*this)->getAttrs(),
2281  {SymbolTable::getSymbolAttrName(),
2282  getGlobalTypeAttrName(), getConstantAttrName(),
2283  getValueAttrName(), getLinkageAttrName(),
2284  getUnnamedAddrAttrName(), getThreadLocal_AttrName(),
2285  getVisibility_AttrName(), getComdatAttrName()});
2286 
2287  // Print the trailing type unless it's a string global.
2288  if (llvm::dyn_cast_or_null<StringAttr>(getValueOrNull()))
2289  return;
2290  p << " : " << getType();
2291 
2292  Region &initializer = getInitializerRegion();
2293  if (!initializer.empty()) {
2294  p << ' ';
2295  p.printRegion(initializer, /*printEntryBlockArgs=*/false);
2296  }
2297 }
2298 
2299 static LogicalResult verifyComdat(Operation *op,
2300  std::optional<SymbolRefAttr> attr) {
2301  if (!attr)
2302  return success();
2303 
2304  auto *comdatSelector = SymbolTable::lookupNearestSymbolFrom(op, *attr);
2305  if (!isa_and_nonnull<ComdatSelectorOp>(comdatSelector))
2306  return op->emitError() << "expected comdat symbol";
2307 
2308  return success();
2309 }
2310 
2311 static LogicalResult verifyBlockTags(LLVMFuncOp funcOp) {
2312  llvm::DenseSet<BlockTagAttr> blockTags;
2313  // Note that presence of `BlockTagOp`s currently can't prevent an unrecheable
2314  // block to be removed by canonicalizer's region simplify pass, which needs to
2315  // be dialect aware to allow extra constraints to be described.
2316  WalkResult res = funcOp.walk([&](BlockTagOp blockTagOp) {
2317  if (blockTags.contains(blockTagOp.getTag())) {
2318  blockTagOp.emitError()
2319  << "duplicate block tag '" << blockTagOp.getTag().getId()
2320  << "' in the same function: ";
2321  return WalkResult::interrupt();
2322  }
2323  blockTags.insert(blockTagOp.getTag());
2324  return WalkResult::advance();
2325  });
2326 
2327  return failure(res.wasInterrupted());
2328 }
2329 
2330 /// Parse common attributes that might show up in the same order in both
2331 /// GlobalOp and AliasOp.
2332 template <typename OpType>
2333 static ParseResult parseCommonGlobalAndAlias(OpAsmParser &parser,
2334  OperationState &result) {
2335  MLIRContext *ctx = parser.getContext();
2336  // Parse optional linkage, default to External.
2337  result.addAttribute(
2338  OpType::getLinkageAttrName(result.name),
2339  LLVM::LinkageAttr::get(ctx, parseOptionalLLVMKeyword<Linkage>(
2340  parser, LLVM::Linkage::External)));
2341 
2342  // Parse optional visibility, default to Default.
2343  result.addAttribute(OpType::getVisibility_AttrName(result.name),
2344  parser.getBuilder().getI64IntegerAttr(
2345  parseOptionalLLVMKeyword<LLVM::Visibility, int64_t>(
2346  parser, LLVM::Visibility::Default)));
2347 
2348  if (succeeded(parser.parseOptionalKeyword("thread_local")))
2349  result.addAttribute(OpType::getThreadLocal_AttrName(result.name),
2350  parser.getBuilder().getUnitAttr());
2351 
2352  // Parse optional UnnamedAddr, default to None.
2353  result.addAttribute(OpType::getUnnamedAddrAttrName(result.name),
2354  parser.getBuilder().getI64IntegerAttr(
2355  parseOptionalLLVMKeyword<UnnamedAddr, int64_t>(
2356  parser, LLVM::UnnamedAddr::None)));
2357 
2358  return success();
2359 }
2360 
2361 // operation ::= `llvm.mlir.global` linkage? visibility?
2362 // (`unnamed_addr` | `local_unnamed_addr`)?
2363 // `thread_local`? `constant`? `@` identifier
2364 // `(` attribute? `)` (`comdat(` symbol-ref-id `)`)?
2365 // attribute-list? (`:` type)? region?
2366 //
2367 // The type can be omitted for string attributes, in which case it will be
2368 // inferred from the value of the string as [strlen(value) x i8].
2369 ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
2370  // Call into common parsing between GlobalOp and AliasOp.
2371  if (parseCommonGlobalAndAlias<GlobalOp>(parser, result).failed())
2372  return failure();
2373 
2374  if (succeeded(parser.parseOptionalKeyword("constant")))
2375  result.addAttribute(getConstantAttrName(result.name),
2376  parser.getBuilder().getUnitAttr());
2377 
2378  StringAttr name;
2379  if (parser.parseSymbolName(name, getSymNameAttrName(result.name),
2380  result.attributes) ||
2381  parser.parseLParen())
2382  return failure();
2383 
2384  Attribute value;
2385  if (parser.parseOptionalRParen()) {
2386  if (parser.parseAttribute(value, getValueAttrName(result.name),
2387  result.attributes) ||
2388  parser.parseRParen())
2389  return failure();
2390  }
2391 
2392  if (succeeded(parser.parseOptionalKeyword("comdat"))) {
2393  SymbolRefAttr comdat;
2394  if (parser.parseLParen() || parser.parseAttribute(comdat) ||
2395  parser.parseRParen())
2396  return failure();
2397 
2398  result.addAttribute(getComdatAttrName(result.name), comdat);
2399  }
2400 
2401  SmallVector<Type, 1> types;
2402  if (parser.parseOptionalAttrDict(result.attributes) ||
2403  parser.parseOptionalColonTypeList(types))
2404  return failure();
2405 
2406  if (types.size() > 1)
2407  return parser.emitError(parser.getNameLoc(), "expected zero or one type");
2408 
2409  Region &initRegion = *result.addRegion();
2410  if (types.empty()) {
2411  if (auto strAttr = llvm::dyn_cast_or_null<StringAttr>(value)) {
2412  MLIRContext *context = parser.getContext();
2413  auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8),
2414  strAttr.getValue().size());
2415  types.push_back(arrayType);
2416  } else {
2417  return parser.emitError(parser.getNameLoc(),
2418  "type can only be omitted for string globals");
2419  }
2420  } else {
2421  OptionalParseResult parseResult =
2422  parser.parseOptionalRegion(initRegion, /*arguments=*/{},
2423  /*argTypes=*/{});
2424  if (parseResult.has_value() && failed(*parseResult))
2425  return failure();
2426  }
2427 
2428  result.addAttribute(getGlobalTypeAttrName(result.name),
2429  TypeAttr::get(types[0]));
2430  return success();
2431 }
2432 
2433 static bool isZeroAttribute(Attribute value) {
2434  if (auto intValue = llvm::dyn_cast<IntegerAttr>(value))
2435  return intValue.getValue().isZero();
2436  if (auto fpValue = llvm::dyn_cast<FloatAttr>(value))
2437  return fpValue.getValue().isZero();
2438  if (auto splatValue = llvm::dyn_cast<SplatElementsAttr>(value))
2439  return isZeroAttribute(splatValue.getSplatValue<Attribute>());
2440  if (auto elementsValue = llvm::dyn_cast<ElementsAttr>(value))
2441  return llvm::all_of(elementsValue.getValues<Attribute>(), isZeroAttribute);
2442  if (auto arrayValue = llvm::dyn_cast<ArrayAttr>(value))
2443  return llvm::all_of(arrayValue.getValue(), isZeroAttribute);
2444  return false;
2445 }
2446 
2447 LogicalResult GlobalOp::verify() {
2448  bool validType = isCompatibleOuterType(getType())
2449  ? !llvm::isa<LLVMVoidType, LLVMTokenType,
2450  LLVMMetadataType, LLVMLabelType>(getType())
2451  : llvm::isa<PointerElementTypeInterface>(getType());
2452  if (!validType)
2453  return emitOpError(
2454  "expects type to be a valid element type for an LLVM global");
2455  if ((*this)->getParentOp() && !satisfiesLLVMModule((*this)->getParentOp()))
2456  return emitOpError("must appear at the module level");
2457 
2458  if (auto strAttr = llvm::dyn_cast_or_null<StringAttr>(getValueOrNull())) {
2459  auto type = llvm::dyn_cast<LLVMArrayType>(getType());
2460  IntegerType elementType =
2461  type ? llvm::dyn_cast<IntegerType>(type.getElementType()) : nullptr;
2462  if (!elementType || elementType.getWidth() != 8 ||
2463  type.getNumElements() != strAttr.getValue().size())
2464  return emitOpError(
2465  "requires an i8 array type of the length equal to that of the string "
2466  "attribute");
2467  }
2468 
2469  if (auto targetExtType = dyn_cast<LLVMTargetExtType>(getType())) {
2470  if (!targetExtType.hasProperty(LLVMTargetExtType::CanBeGlobal))
2471  return emitOpError()
2472  << "this target extension type cannot be used in a global";
2473 
2474  if (Attribute value = getValueOrNull())
2475  return emitOpError() << "global with target extension type can only be "
2476  "initialized with zero-initializer";
2477  }
2478 
2479  if (getLinkage() == Linkage::Common) {
2480  if (Attribute value = getValueOrNull()) {
2481  if (!isZeroAttribute(value)) {
2482  return emitOpError()
2483  << "expected zero value for '"
2484  << stringifyLinkage(Linkage::Common) << "' linkage";
2485  }
2486  }
2487  }
2488 
2489  if (getLinkage() == Linkage::Appending) {
2490  if (!llvm::isa<LLVMArrayType>(getType())) {
2491  return emitOpError() << "expected array type for '"
2492  << stringifyLinkage(Linkage::Appending)
2493  << "' linkage";
2494  }
2495  }
2496 
2497  if (failed(verifyComdat(*this, getComdat())))
2498  return failure();
2499 
2500  std::optional<uint64_t> alignAttr = getAlignment();
2501  if (alignAttr.has_value()) {
2502  uint64_t value = alignAttr.value();
2503  if (!llvm::isPowerOf2_64(value))
2504  return emitError() << "alignment attribute is not a power of 2";
2505  }
2506 
2507  return success();
2508 }
2509 
2510 LogicalResult GlobalOp::verifyRegions() {
2511  if (Block *b = getInitializerBlock()) {
2512  ReturnOp ret = cast<ReturnOp>(b->getTerminator());
2513  if (ret.operand_type_begin() == ret.operand_type_end())
2514  return emitOpError("initializer region cannot return void");
2515  if (*ret.operand_type_begin() != getType())
2516  return emitOpError("initializer region type ")
2517  << *ret.operand_type_begin() << " does not match global type "
2518  << getType();
2519 
2520  for (Operation &op : *b) {
2521  auto iface = dyn_cast<MemoryEffectOpInterface>(op);
2522  if (!iface || !iface.hasNoEffect())
2523  return op.emitError()
2524  << "ops with side effects not allowed in global initializers";
2525  }
2526 
2527  if (getValueOrNull())
2528  return emitOpError("cannot have both initializer value and region");
2529  }
2530 
2531  return success();
2532 }
2533 
2534 //===----------------------------------------------------------------------===//
2535 // LLVM::GlobalCtorsOp
2536 //===----------------------------------------------------------------------===//
2537 
2538 static LogicalResult checkGlobalXtorData(Operation *op, ArrayAttr data) {
2539  if (data.empty())
2540  return success();
2541 
2542  if (llvm::all_of(data.getAsRange<Attribute>(), [](Attribute v) {
2543  return isa<FlatSymbolRefAttr, ZeroAttr>(v);
2544  }))
2545  return success();
2546  return op->emitError("data element must be symbol or #llvm.zero");
2547 }
2548 
2549 LogicalResult
2550 GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2551  for (Attribute ctor : getCtors()) {
2552  if (failed(verifySymbolAttrUse(llvm::cast<FlatSymbolRefAttr>(ctor), *this,
2553  symbolTable)))
2554  return failure();
2555  }
2556  return success();
2557 }
2558 
2559 LogicalResult GlobalCtorsOp::verify() {
2560  if (checkGlobalXtorData(*this, getData()).failed())
2561  return failure();
2562 
2563  if (getCtors().size() == getPriorities().size() &&
2564  getCtors().size() == getData().size())
2565  return success();
2566  return emitError(
2567  "ctors, priorities, and data must have the same number of elements");
2568 }
2569 
2570 //===----------------------------------------------------------------------===//
2571 // LLVM::GlobalDtorsOp
2572 //===----------------------------------------------------------------------===//
2573 
2574 LogicalResult
2575 GlobalDtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2576  for (Attribute dtor : getDtors()) {
2577  if (failed(verifySymbolAttrUse(llvm::cast<FlatSymbolRefAttr>(dtor), *this,
2578  symbolTable)))
2579  return failure();
2580  }
2581  return success();
2582 }
2583 
2584 LogicalResult GlobalDtorsOp::verify() {
2585  if (checkGlobalXtorData(*this, getData()).failed())
2586  return failure();
2587 
2588  if (getDtors().size() == getPriorities().size() &&
2589  getDtors().size() == getData().size())
2590  return success();
2591  return emitError(
2592  "dtors, priorities, and data must have the same number of elements");
2593 }
2594 
2595 //===----------------------------------------------------------------------===//
2596 // Builder, printer and verifier for LLVM::AliasOp.
2597 //===----------------------------------------------------------------------===//
2598 
2599 void AliasOp::build(OpBuilder &builder, OperationState &result, Type type,
2600  Linkage linkage, StringRef name, bool dsoLocal,
2601  bool threadLocal, ArrayRef<NamedAttribute> attrs) {
2602  result.addAttribute(getSymNameAttrName(result.name),
2603  builder.getStringAttr(name));
2604  result.addAttribute(getAliasTypeAttrName(result.name), TypeAttr::get(type));
2605  if (dsoLocal)
2606  result.addAttribute(getDsoLocalAttrName(result.name),
2607  builder.getUnitAttr());
2608  if (threadLocal)
2609  result.addAttribute(getThreadLocal_AttrName(result.name),
2610  builder.getUnitAttr());
2611 
2612  result.addAttribute(getLinkageAttrName(result.name),
2613  LinkageAttr::get(builder.getContext(), linkage));
2614  result.attributes.append(attrs.begin(), attrs.end());
2615 
2616  result.addRegion();
2617 }
2618 
2619 void AliasOp::print(OpAsmPrinter &p) {
2620  printCommonGlobalAndAlias<AliasOp>(p, *this);
2621 
2622  p.printSymbolName(getSymName());
2623  p.printOptionalAttrDict((*this)->getAttrs(),
2624  {SymbolTable::getSymbolAttrName(),
2625  getAliasTypeAttrName(), getLinkageAttrName(),
2626  getUnnamedAddrAttrName(), getThreadLocal_AttrName(),
2627  getVisibility_AttrName()});
2628 
2629  // Print the trailing type.
2630  p << " : " << getType() << ' ';
2631  // Print the initializer region.
2632  p.printRegion(getInitializerRegion(), /*printEntryBlockArgs=*/false);
2633 }
2634 
2635 // operation ::= `llvm.mlir.alias` linkage? visibility?
2636 // (`unnamed_addr` | `local_unnamed_addr`)?
2637 // `thread_local`? `@` identifier
2638 // `(` attribute? `)`
2639 // attribute-list? `:` type region
2640 //
2641 ParseResult AliasOp::parse(OpAsmParser &parser, OperationState &result) {
2642  // Call into common parsing between GlobalOp and AliasOp.
2643  if (parseCommonGlobalAndAlias<AliasOp>(parser, result).failed())
2644  return failure();
2645 
2646  StringAttr name;
2647  if (parser.parseSymbolName(name, getSymNameAttrName(result.name),
2648  result.attributes))
2649  return failure();
2650 
2651  SmallVector<Type, 1> types;
2652  if (parser.parseOptionalAttrDict(result.attributes) ||
2653  parser.parseOptionalColonTypeList(types))
2654  return failure();
2655 
2656  if (types.size() > 1)
2657  return parser.emitError(parser.getNameLoc(), "expected zero or one type");
2658 
2659  Region &initRegion = *result.addRegion();
2660  if (parser.parseRegion(initRegion).failed())
2661  return failure();
2662 
2663  result.addAttribute(getAliasTypeAttrName(result.name),
2664  TypeAttr::get(types[0]));
2665  return success();
2666 }
2667 
2668 LogicalResult AliasOp::verify() {
2669  bool validType = isCompatibleOuterType(getType())
2670  ? !llvm::isa<LLVMVoidType, LLVMTokenType,
2671  LLVMMetadataType, LLVMLabelType>(getType())
2672  : llvm::isa<PointerElementTypeInterface>(getType());
2673  if (!validType)
2674  return emitOpError(
2675  "expects type to be a valid element type for an LLVM global alias");
2676 
2677  // This matches LLVM IR verification logic, see llvm/lib/IR/Verifier.cpp
2678  switch (getLinkage()) {
2679  case Linkage::External:
2680  case Linkage::Internal:
2681  case Linkage::Private:
2682  case Linkage::Weak:
2683  case Linkage::WeakODR:
2684  case Linkage::Linkonce:
2685  case Linkage::LinkonceODR:
2686  case Linkage::AvailableExternally:
2687  break;
2688  default:
2689  return emitOpError()
2690  << "'" << stringifyLinkage(getLinkage())
2691  << "' linkage not supported in aliases, available options: private, "
2692  "internal, linkonce, weak, linkonce_odr, weak_odr, external or "
2693  "available_externally";
2694  }
2695 
2696  return success();
2697 }
2698 
2699 LogicalResult AliasOp::verifyRegions() {
2700  Block &b = getInitializerBlock();
2701  auto ret = cast<ReturnOp>(b.getTerminator());
2702  if (ret.getNumOperands() == 0 ||
2703  !isa<LLVM::LLVMPointerType>(ret.getOperand(0).getType()))
2704  return emitOpError("initializer region must always return a pointer");
2705 
2706  for (Operation &op : b) {
2707  auto iface = dyn_cast<MemoryEffectOpInterface>(op);
2708  if (!iface || !iface.hasNoEffect())
2709  return op.emitError()
2710  << "ops with side effects are not allowed in alias initializers";
2711  }
2712 
2713  return success();
2714 }
2715 
2716 unsigned AliasOp::getAddrSpace() {
2717  Block &initializer = getInitializerBlock();
2718  auto ret = cast<ReturnOp>(initializer.getTerminator());
2719  auto ptrTy = cast<LLVMPointerType>(ret.getOperand(0).getType());
2720  return ptrTy.getAddressSpace();
2721 }
2722 
2723 //===----------------------------------------------------------------------===//
2724 // IFuncOp
2725 //===----------------------------------------------------------------------===//
2726 
2727 void IFuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
2728  Type iFuncType, StringRef resolverName, Type resolverType,
2729  Linkage linkage, LLVM::Visibility visibility) {
2730  return build(builder, result, name, iFuncType, resolverName, resolverType,
2731  linkage, /*dso_local=*/false, /*address_space=*/0,
2732  UnnamedAddr::None, visibility);
2733 }
2734 
2735 LogicalResult IFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2736  Operation *symbol =
2737  symbolTable.lookupSymbolIn(parentLLVMModule(*this), getResolverAttr());
2738  // This matches LLVM IR verification logic, see llvm/lib/IR/Verifier.cpp
2739  auto resolver = dyn_cast<LLVMFuncOp>(symbol);
2740  auto alias = dyn_cast<AliasOp>(symbol);
2741  while (alias) {
2742  Block &initBlock = alias.getInitializerBlock();
2743  auto returnOp = cast<ReturnOp>(initBlock.getTerminator());
2744  auto addrOp = returnOp.getArg().getDefiningOp<AddressOfOp>();
2745  // FIXME: This is a best effort solution. The AliasOp body might be more
2746  // complex and in that case we bail out with success. To completely match
2747  // the LLVM IR logic it would be necessary to implement proper alias and
2748  // cast stripping.
2749  if (!addrOp)
2750  return success();
2751  resolver = addrOp.getFunction(symbolTable);
2752  alias = addrOp.getAlias(symbolTable);
2753  }
2754  if (!resolver)
2755  return emitOpError("must have a function resolver");
2756  Linkage linkage = resolver.getLinkage();
2757  if (resolver.isExternal() || linkage == Linkage::AvailableExternally)
2758  return emitOpError("resolver must be a definition");
2759  if (!isa<LLVMPointerType>(resolver.getFunctionType().getReturnType()))
2760  return emitOpError("resolver must return a pointer");
2761  auto resolverPtr = dyn_cast<LLVMPointerType>(getResolverType());
2762  if (!resolverPtr || resolverPtr.getAddressSpace() != getAddressSpace())
2763  return emitOpError("resolver has incorrect type");
2764  return success();
2765 }
2766 
2767 LogicalResult IFuncOp::verify() {
2768  switch (getLinkage()) {
2769  case Linkage::External:
2770  case Linkage::Internal:
2771  case Linkage::Private:
2772  case Linkage::Weak:
2773  case Linkage::WeakODR:
2774  case Linkage::Linkonce:
2775  case Linkage::LinkonceODR:
2776  break;
2777  default:
2778  return emitOpError() << "'" << stringifyLinkage(getLinkage())
2779  << "' linkage not supported in ifuncs, available "
2780  "options: private, internal, linkonce, weak, "
2781  "linkonce_odr, weak_odr, or external linkage";
2782  }
2783  return success();
2784 }
2785 
2786 //===----------------------------------------------------------------------===//
2787 // ShuffleVectorOp
2788 //===----------------------------------------------------------------------===//
2789 
2790 void ShuffleVectorOp::build(OpBuilder &builder, OperationState &state, Value v1,
2791  Value v2, DenseI32ArrayAttr mask,
2792  ArrayRef<NamedAttribute> attrs) {
2793  auto containerType = v1.getType();
2794  auto vType = LLVM::getVectorType(
2795  cast<VectorType>(containerType).getElementType(), mask.size(),
2796  LLVM::isScalableVectorType(containerType));
2797  build(builder, state, vType, v1, v2, mask);
2798  state.addAttributes(attrs);
2799 }
2800 
2801 void ShuffleVectorOp::build(OpBuilder &builder, OperationState &state, Value v1,
2802  Value v2, ArrayRef<int32_t> mask) {
2803  build(builder, state, v1, v2, builder.getDenseI32ArrayAttr(mask));
2804 }
2805 
2806 /// Build the result type of a shuffle vector operation.
2807 static ParseResult parseShuffleType(AsmParser &parser, Type v1Type,
2808  Type &resType, DenseI32ArrayAttr mask) {
2809  if (!LLVM::isCompatibleVectorType(v1Type))
2810  return parser.emitError(parser.getCurrentLocation(),
2811  "expected an LLVM compatible vector type");
2812  resType =
2813  LLVM::getVectorType(cast<VectorType>(v1Type).getElementType(),
2814  mask.size(), LLVM::isScalableVectorType(v1Type));
2815  return success();
2816 }
2817 
2818 /// Nothing to do when the result type is inferred.
2819 static void printShuffleType(AsmPrinter &printer, Operation *op, Type v1Type,
2820  Type resType, DenseI32ArrayAttr mask) {}
2821 
2822 LogicalResult ShuffleVectorOp::verify() {
2823  if (LLVM::isScalableVectorType(getV1().getType()) &&
2824  llvm::any_of(getMask(), [](int32_t v) { return v != 0; }))
2825  return emitOpError("expected a splat operation for scalable vectors");
2826  return success();
2827 }
2828 
2829 // Folding for shufflevector op when v1 is single element 1D vector
2830 // and the mask is a single zero. OpFoldResult will be v1 in this case.
2831 OpFoldResult ShuffleVectorOp::fold(FoldAdaptor adaptor) {
2832  // Check if operand 0 is a single element vector.
2833  auto vecType = llvm::dyn_cast<VectorType>(getV1().getType());
2834  if (!vecType || vecType.getRank() != 1 || vecType.getNumElements() != 1)
2835  return {};
2836  // Check if the mask is a single zero.
2837  // Note: The mask is guaranteed to be non-empty.
2838  if (getMask().size() != 1 || getMask()[0] != 0)
2839  return {};
2840  return getV1();
2841 }
2842 
2843 //===----------------------------------------------------------------------===//
2844 // Implementations for LLVM::LLVMFuncOp.
2845 //===----------------------------------------------------------------------===//
2846 
2847 // Add the entry block to the function.
2848 Block *LLVMFuncOp::addEntryBlock(OpBuilder &builder) {
2849  assert(empty() && "function already has an entry block");
2850  OpBuilder::InsertionGuard g(builder);
2851  Block *entry = builder.createBlock(&getBody());
2852 
2853  // FIXME: Allow passing in proper locations for the entry arguments.
2854  LLVMFunctionType type = getFunctionType();
2855  for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
2856  entry->addArgument(type.getParamType(i), getLoc());
2857  return entry;
2858 }
2859 
2860 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result,
2861  StringRef name, Type type, LLVM::Linkage linkage,
2862  bool dsoLocal, CConv cconv, SymbolRefAttr comdat,
2864  ArrayRef<DictionaryAttr> argAttrs,
2865  std::optional<uint64_t> functionEntryCount) {
2866  result.addRegion();
2868  builder.getStringAttr(name));
2869  result.addAttribute(getFunctionTypeAttrName(result.name),
2870  TypeAttr::get(type));
2871  result.addAttribute(getLinkageAttrName(result.name),
2872  LinkageAttr::get(builder.getContext(), linkage));
2873  result.addAttribute(getCConvAttrName(result.name),
2874  CConvAttr::get(builder.getContext(), cconv));
2875  result.attributes.append(attrs.begin(), attrs.end());
2876  if (dsoLocal)
2877  result.addAttribute(getDsoLocalAttrName(result.name),
2878  builder.getUnitAttr());
2879  if (comdat)
2880  result.addAttribute(getComdatAttrName(result.name), comdat);
2881  if (functionEntryCount)
2882  result.addAttribute(getFunctionEntryCountAttrName(result.name),
2883  builder.getI64IntegerAttr(functionEntryCount.value()));
2884  if (argAttrs.empty())
2885  return;
2886 
2887  assert(llvm::cast<LLVMFunctionType>(type).getNumParams() == argAttrs.size() &&
2888  "expected as many argument attribute lists as arguments");
2890  builder, result, argAttrs, /*resultAttrs=*/{},
2891  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
2892 }
2893 
2894 // Builds an LLVM function type from the given lists of input and output types.
2895 // Returns a null type if any of the types provided are non-LLVM types, or if
2896 // there is more than one output type.
2897 static Type
2899  ArrayRef<Type> outputs,
2901  Builder &b = parser.getBuilder();
2902  if (outputs.size() > 1) {
2903  parser.emitError(loc, "failed to construct function type: expected zero or "
2904  "one function result");
2905  return {};
2906  }
2907 
2908  // Convert inputs to LLVM types, exit early on error.
2909  SmallVector<Type, 4> llvmInputs;
2910  for (auto t : inputs) {
2911  if (!isCompatibleType(t)) {
2912  parser.emitError(loc, "failed to construct function type: expected LLVM "
2913  "type for function arguments");
2914  return {};
2915  }
2916  llvmInputs.push_back(t);
2917  }
2918 
2919  // No output is denoted as "void" in LLVM type system.
2920  Type llvmOutput =
2921  outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front();
2922  if (!isCompatibleType(llvmOutput)) {
2923  parser.emitError(loc, "failed to construct function type: expected LLVM "
2924  "type for function results")
2925  << llvmOutput;
2926  return {};
2927  }
2928  return LLVMFunctionType::get(llvmOutput, llvmInputs,
2929  variadicFlag.isVariadic());
2930 }
2931 
2932 // Parses an LLVM function.
2933 //
2934 // operation ::= `llvm.func` linkage? cconv? function-signature
2935 // (`comdat(` symbol-ref-id `)`)?
2936 // function-attributes?
2937 // function-body
2938 //
2939 ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) {
2940  // Default to external linkage if no keyword is provided.
2941  result.addAttribute(getLinkageAttrName(result.name),
2942  LinkageAttr::get(parser.getContext(),
2943  parseOptionalLLVMKeyword<Linkage>(
2944  parser, LLVM::Linkage::External)));
2945 
2946  // Parse optional visibility, default to Default.
2947  result.addAttribute(getVisibility_AttrName(result.name),
2948  parser.getBuilder().getI64IntegerAttr(
2949  parseOptionalLLVMKeyword<LLVM::Visibility, int64_t>(
2950  parser, LLVM::Visibility::Default)));
2951 
2952  // Parse optional UnnamedAddr, default to None.
2953  result.addAttribute(getUnnamedAddrAttrName(result.name),
2954  parser.getBuilder().getI64IntegerAttr(
2955  parseOptionalLLVMKeyword<UnnamedAddr, int64_t>(
2956  parser, LLVM::UnnamedAddr::None)));
2957 
2958  // Default to C Calling Convention if no keyword is provided.
2959  result.addAttribute(
2960  getCConvAttrName(result.name),
2961  CConvAttr::get(parser.getContext(),
2962  parseOptionalLLVMKeyword<CConv>(parser, LLVM::CConv::C)));
2963 
2964  StringAttr nameAttr;
2966  SmallVector<DictionaryAttr> resultAttrs;
2967  SmallVector<Type> resultTypes;
2968  bool isVariadic;
2969 
2970  auto signatureLocation = parser.getCurrentLocation();
2971  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2972  result.attributes) ||
2974  parser, /*allowVariadic=*/true, entryArgs, isVariadic, resultTypes,
2975  resultAttrs))
2976  return failure();
2977 
2978  SmallVector<Type> argTypes;
2979  for (auto &arg : entryArgs)
2980  argTypes.push_back(arg.type);
2981  auto type =
2982  buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
2984  if (!type)
2985  return failure();
2986  result.addAttribute(getFunctionTypeAttrName(result.name),
2987  TypeAttr::get(type));
2988 
2989  if (succeeded(parser.parseOptionalKeyword("vscale_range"))) {
2990  int64_t minRange, maxRange;
2991  if (parser.parseLParen() || parser.parseInteger(minRange) ||
2992  parser.parseComma() || parser.parseInteger(maxRange) ||
2993  parser.parseRParen())
2994  return failure();
2995  auto intTy = IntegerType::get(parser.getContext(), 32);
2996  result.addAttribute(
2997  getVscaleRangeAttrName(result.name),
2999  IntegerAttr::get(intTy, minRange),
3000  IntegerAttr::get(intTy, maxRange)));
3001  }
3002  // Parse the optional comdat selector.
3003  if (succeeded(parser.parseOptionalKeyword("comdat"))) {
3004  SymbolRefAttr comdat;
3005  if (parser.parseLParen() || parser.parseAttribute(comdat) ||
3006  parser.parseRParen())
3007  return failure();
3008 
3009  result.addAttribute(getComdatAttrName(result.name), comdat);
3010  }
3011 
3013  return failure();
3015  parser.getBuilder(), result, entryArgs, resultAttrs,
3016  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
3017 
3018  auto *body = result.addRegion();
3019  OptionalParseResult parseResult =
3020  parser.parseOptionalRegion(*body, entryArgs);
3021  return failure(parseResult.has_value() && failed(*parseResult));
3022 }
3023 
3024 // Print the LLVMFuncOp. Collects argument and result types and passes them to
3025 // helper functions. Drops "void" result since it cannot be parsed back. Skips
3026 // the external linkage since it is the default value.
3028  p << ' ';
3029  if (getLinkage() != LLVM::Linkage::External)
3030  p << stringifyLinkage(getLinkage()) << ' ';
3031  StringRef visibility = stringifyVisibility(getVisibility_());
3032  if (!visibility.empty())
3033  p << visibility << ' ';
3034  if (auto unnamedAddr = getUnnamedAddr()) {
3035  StringRef str = stringifyUnnamedAddr(*unnamedAddr);
3036  if (!str.empty())
3037  p << str << ' ';
3038  }
3039  if (getCConv() != LLVM::CConv::C)
3040  p << stringifyCConv(getCConv()) << ' ';
3041 
3042  p.printSymbolName(getName());
3043 
3044  LLVMFunctionType fnType = getFunctionType();
3045  SmallVector<Type, 8> argTypes;
3046  SmallVector<Type, 1> resTypes;
3047  argTypes.reserve(fnType.getNumParams());
3048  for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i)
3049  argTypes.push_back(fnType.getParamType(i));
3050 
3051  Type returnType = fnType.getReturnType();
3052  if (!llvm::isa<LLVMVoidType>(returnType))
3053  resTypes.push_back(returnType);
3054 
3056  isVarArg(), resTypes);
3057 
3058  // Print vscale range if present
3059  if (std::optional<VScaleRangeAttr> vscale = getVscaleRange())
3060  p << " vscale_range(" << vscale->getMinRange().getInt() << ", "
3061  << vscale->getMaxRange().getInt() << ')';
3062 
3063  // Print the optional comdat selector.
3064  if (auto comdat = getComdat())
3065  p << " comdat(" << *comdat << ')';
3066 
3068  p, *this,
3069  {getFunctionTypeAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(),
3070  getLinkageAttrName(), getCConvAttrName(), getVisibility_AttrName(),
3071  getComdatAttrName(), getUnnamedAddrAttrName(),
3072  getVscaleRangeAttrName()});
3073 
3074  // Print the body if this is not an external function.
3075  Region &body = getBody();
3076  if (!body.empty()) {
3077  p << ' ';
3078  p.printRegion(body, /*printEntryBlockArgs=*/false,
3079  /*printBlockTerminators=*/true);
3080  }
3081 }
3082 
3083 // Verifies LLVM- and implementation-specific properties of the LLVM func Op:
3084 // - functions don't have 'common' linkage
3085 // - external functions have 'external' or 'extern_weak' linkage;
3086 // - vararg is (currently) only supported for external functions;
3087 LogicalResult LLVMFuncOp::verify() {
3088  if (getLinkage() == LLVM::Linkage::Common)
3089  return emitOpError() << "functions cannot have '"
3090  << stringifyLinkage(LLVM::Linkage::Common)
3091  << "' linkage";
3092 
3093  if (failed(verifyComdat(*this, getComdat())))
3094  return failure();
3095 
3096  if (isExternal()) {
3097  if (getLinkage() != LLVM::Linkage::External &&
3098  getLinkage() != LLVM::Linkage::ExternWeak)
3099  return emitOpError() << "external functions must have '"
3100  << stringifyLinkage(LLVM::Linkage::External)
3101  << "' or '"
3102  << stringifyLinkage(LLVM::Linkage::ExternWeak)
3103  << "' linkage";
3104  return success();
3105  }
3106 
3107  // In LLVM IR, these attributes are composed by convention, not by design.
3108  if (isNoInline() && isAlwaysInline())
3109  return emitError("no_inline and always_inline attributes are incompatible");
3110 
3111  if (isOptimizeNone() && !isNoInline())
3112  return emitOpError("with optimize_none must also be no_inline");
3113 
3114  Type landingpadResultTy;
3115  StringRef diagnosticMessage;
3116  bool isLandingpadTypeConsistent =
3117  !walk([&](Operation *op) {
3118  const auto checkType = [&](Type type, StringRef errorMessage) {
3119  if (!landingpadResultTy) {
3120  landingpadResultTy = type;
3121  return WalkResult::advance();
3122  }
3123  if (landingpadResultTy != type) {
3124  diagnosticMessage = errorMessage;
3125  return WalkResult::interrupt();
3126  }
3127  return WalkResult::advance();
3128  };
3130  .Case<LandingpadOp>([&](auto landingpad) {
3131  constexpr StringLiteral errorMessage =
3132  "'llvm.landingpad' should have a consistent result type "
3133  "inside a function";
3134  return checkType(landingpad.getType(), errorMessage);
3135  })
3136  .Case<ResumeOp>([&](auto resume) {
3137  constexpr StringLiteral errorMessage =
3138  "'llvm.resume' should have a consistent input type inside a "
3139  "function";
3140  return checkType(resume.getValue().getType(), errorMessage);
3141  })
3142  .Default([](auto) { return WalkResult::skip(); });
3143  }).wasInterrupted();
3144  if (!isLandingpadTypeConsistent) {
3145  assert(!diagnosticMessage.empty() &&
3146  "Expecting a non-empty diagnostic message");
3147  return emitError(diagnosticMessage);
3148  }
3149 
3150  if (failed(verifyBlockTags(*this)))
3151  return failure();
3152 
3153  return success();
3154 }
3155 
3156 /// Verifies LLVM- and implementation-specific properties of the LLVM func Op:
3157 /// - entry block arguments are of LLVM types.
3158 LogicalResult LLVMFuncOp::verifyRegions() {
3159  if (isExternal())
3160  return success();
3161 
3162  unsigned numArguments = getFunctionType().getNumParams();
3163  Block &entryBlock = front();
3164  for (unsigned i = 0; i < numArguments; ++i) {
3165  Type argType = entryBlock.getArgument(i).getType();
3166  if (!isCompatibleType(argType))
3167  return emitOpError("entry block argument #")
3168  << i << " is not of LLVM type";
3169  }
3170 
3171  return success();
3172 }
3173 
3174 Region *LLVMFuncOp::getCallableRegion() {
3175  if (isExternal())
3176  return nullptr;
3177  return &getBody();
3178 }
3179 
3180 //===----------------------------------------------------------------------===//
3181 // UndefOp.
3182 //===----------------------------------------------------------------------===//
3183 
3184 /// Fold an undef operation to a dedicated undef attribute.
3185 OpFoldResult LLVM::UndefOp::fold(FoldAdaptor) {
3186  return LLVM::UndefAttr::get(getContext());
3187 }
3188 
3189 //===----------------------------------------------------------------------===//
3190 // PoisonOp.
3191 //===----------------------------------------------------------------------===//
3192 
3193 /// Fold a poison operation to a dedicated poison attribute.
3194 OpFoldResult LLVM::PoisonOp::fold(FoldAdaptor) {
3196 }
3197 
3198 //===----------------------------------------------------------------------===//
3199 // ZeroOp.
3200 //===----------------------------------------------------------------------===//
3201 
3202 LogicalResult LLVM::ZeroOp::verify() {
3203  if (auto targetExtType = dyn_cast<LLVMTargetExtType>(getType()))
3204  if (!targetExtType.hasProperty(LLVM::LLVMTargetExtType::HasZeroInit))
3205  return emitOpError()
3206  << "target extension type does not support zero-initializer";
3207 
3208  return success();
3209 }
3210 
3211 /// Fold a zero operation to a builtin zero attribute when possible and fall
3212 /// back to a dedicated zero attribute.
3213 OpFoldResult LLVM::ZeroOp::fold(FoldAdaptor) {
3215  if (result)
3216  return result;
3217  return LLVM::ZeroAttr::get(getContext());
3218 }
3219 
3220 //===----------------------------------------------------------------------===//
3221 // ConstantOp.
3222 //===----------------------------------------------------------------------===//
3223 
3224 /// Compute the total number of elements in the given type, also taking into
3225 /// account nested types. Supported types are `VectorType` and `LLVMArrayType`.
3226 /// Everything else is treated as a scalar.
3227 static int64_t getNumElements(Type t) {
3228  if (auto vecType = dyn_cast<VectorType>(t)) {
3229  assert(!vecType.isScalable() &&
3230  "number of elements of a scalable vector type is unknown");
3231  return vecType.getNumElements() * getNumElements(vecType.getElementType());
3232  }
3233  if (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(t))
3234  return arrayType.getNumElements() *
3235  getNumElements(arrayType.getElementType());
3236  return 1;
3237 }
3238 
3239 /// Determine the element type of `type`. Supported types are `VectorType`,
3240 /// `TensorType`, and `LLVMArrayType`. Everything else is treated as a scalar.
3241 static Type getElementType(Type type) {
3242  while (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(type))
3243  type = arrayType.getElementType();
3244  if (auto vecType = dyn_cast<VectorType>(type))
3245  return vecType.getElementType();
3246  if (auto tenType = dyn_cast<TensorType>(type))
3247  return tenType.getElementType();
3248  return type;
3249 }
3250 
3251 /// Check if the given type is a scalable vector type or a vector/array type
3252 /// that contains a nested scalable vector type.
3253 static bool hasScalableVectorType(Type t) {
3254  if (auto vecType = dyn_cast<VectorType>(t)) {
3255  if (vecType.isScalable())
3256  return true;
3257  return hasScalableVectorType(vecType.getElementType());
3258  }
3259  if (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(t))
3260  return hasScalableVectorType(arrayType.getElementType());
3261  return false;
3262 }
3263 
3264 /// Verifies the constant array represented by `arrayAttr` matches the provided
3265 /// `arrayType`.
3266 static LogicalResult verifyStructArrayConstant(LLVM::ConstantOp op,
3267  LLVM::LLVMArrayType arrayType,
3268  ArrayAttr arrayAttr, int dim) {
3269  if (arrayType.getNumElements() != arrayAttr.size())
3270  return op.emitOpError()
3271  << "array attribute size does not match array type size in "
3272  "dimension "
3273  << dim << ": " << arrayAttr.size() << " vs. "
3274  << arrayType.getNumElements();
3275 
3276  llvm::DenseSet<Attribute> elementsVerified;
3277 
3278  // Recursively verify sub-dimensions for multidimensional arrays.
3279  if (auto subArrayType =
3280  dyn_cast<LLVM::LLVMArrayType>(arrayType.getElementType())) {
3281  for (auto [idx, elementAttr] : llvm::enumerate(arrayAttr))
3282  if (elementsVerified.insert(elementAttr).second) {
3283  if (isa<LLVM::ZeroAttr, LLVM::UndefAttr>(elementAttr))
3284  continue;
3285  auto subArrayAttr = dyn_cast<ArrayAttr>(elementAttr);
3286  if (!subArrayAttr)
3287  return op.emitOpError()
3288  << "nested attribute for sub-array in dimension " << dim
3289  << " at index " << idx
3290  << " must be a zero, or undef, or array attribute";
3291  if (failed(verifyStructArrayConstant(op, subArrayType, subArrayAttr,
3292  dim + 1)))
3293  return failure();
3294  }
3295  return success();
3296  }
3297 
3298  // Forbid usages of ArrayAttr for simple array types that should use
3299  // DenseElementsAttr instead. Note that there would be a use case for such
3300  // array types when one element value is obtained via a ptr-to-int conversion
3301  // from a symbol and cannot be represented in a DenseElementsAttr, but no MLIR
3302  // user needs this so far, and it seems better to avoid people misusing the
3303  // ArrayAttr for simple types.
3304  auto structType = dyn_cast<LLVM::LLVMStructType>(arrayType.getElementType());
3305  if (!structType)
3306  return op.emitOpError() << "for array with an array attribute must have a "
3307  "struct element type";
3308 
3309  // Shallow verification that leaf attributes are appropriate as struct initial
3310  // value.
3311  size_t numStructElements = structType.getBody().size();
3312  for (auto [idx, elementAttr] : llvm::enumerate(arrayAttr)) {
3313  if (elementsVerified.insert(elementAttr).second) {
3314  if (isa<LLVM::ZeroAttr, LLVM::UndefAttr>(elementAttr))
3315  continue;
3316  auto subArrayAttr = dyn_cast<ArrayAttr>(elementAttr);
3317  if (!subArrayAttr)
3318  return op.emitOpError()
3319  << "nested attribute for struct element at index " << idx
3320  << " must be a zero, or undef, or array attribute";
3321  if (subArrayAttr.size() != numStructElements)
3322  return op.emitOpError()
3323  << "nested array attribute size for struct element at index "
3324  << idx << " must match struct size: " << subArrayAttr.size()
3325  << " vs. " << numStructElements;
3326  }
3327  }
3328 
3329  return success();
3330 }
3331 
3332 LogicalResult LLVM::ConstantOp::verify() {
3333  if (StringAttr sAttr = llvm::dyn_cast<StringAttr>(getValue())) {
3334  auto arrayType = llvm::dyn_cast<LLVMArrayType>(getType());
3335  if (!arrayType || arrayType.getNumElements() != sAttr.getValue().size() ||
3336  !arrayType.getElementType().isInteger(8)) {
3337  return emitOpError() << "expected array type of "
3338  << sAttr.getValue().size()
3339  << " i8 elements for the string constant";
3340  }
3341  return success();
3342  }
3343  if (auto structType = dyn_cast<LLVMStructType>(getType())) {
3344  auto arrayAttr = dyn_cast<ArrayAttr>(getValue());
3345  if (!arrayAttr)
3346  return emitOpError() << "expected array attribute for struct type";
3347 
3348  ArrayRef<Type> elementTypes = structType.getBody();
3349  if (arrayAttr.size() != elementTypes.size()) {
3350  return emitOpError() << "expected array attribute of size "
3351  << elementTypes.size();
3352  }
3353  for (auto [i, attr, type] : llvm::enumerate(arrayAttr, elementTypes)) {
3354  if (!type.isSignlessIntOrIndexOrFloat()) {
3355  return emitOpError() << "expected struct element types to be floating "
3356  "point type or integer type";
3357  }
3358  if (!isa<FloatAttr, IntegerAttr>(attr)) {
3359  return emitOpError() << "expected element of array attribute to be "
3360  "floating point or integer";
3361  }
3362  if (cast<TypedAttr>(attr).getType() != type)
3363  return emitOpError()
3364  << "struct element at index " << i << " is of wrong type";
3365  }
3366 
3367  return success();
3368  }
3369  if (auto targetExtType = dyn_cast<LLVMTargetExtType>(getType()))
3370  return emitOpError() << "does not support target extension type.";
3371 
3372  // Check that an attribute whose element type has floating point semantics
3373  // `attributeFloatSemantics` is compatible with a type whose element type
3374  // is `constantElementType`.
3375  //
3376  // Requirement is that either
3377  // 1) They have identical floating point types.
3378  // 2) `constantElementType` is an integer type of the same width as the float
3379  // attribute. This is to support builtin MLIR float types without LLVM
3380  // equivalents, see comments in getLLVMConstant for more details.
3381  auto verifyFloatSemantics =
3382  [this](const llvm::fltSemantics &attributeFloatSemantics,
3383  Type constantElementType) -> LogicalResult {
3384  if (auto floatType = dyn_cast<FloatType>(constantElementType)) {
3385  if (&floatType.getFloatSemantics() != &attributeFloatSemantics) {
3386  return emitOpError()
3387  << "attribute and type have different float semantics";
3388  }
3389  return success();
3390  }
3391  unsigned floatWidth = APFloat::getSizeInBits(attributeFloatSemantics);
3392  if (isa<IntegerType>(constantElementType)) {
3393  if (!constantElementType.isInteger(floatWidth))
3394  return emitOpError() << "expected integer type of width " << floatWidth;
3395 
3396  return success();
3397  }
3398  return success();
3399  };
3400 
3401  // Verification of IntegerAttr, FloatAttr, ElementsAttr, ArrayAttr.
3402  if (isa<IntegerAttr>(getValue())) {
3403  if (!llvm::isa<IntegerType>(getType()))
3404  return emitOpError() << "expected integer type";
3405  } else if (auto floatAttr = dyn_cast<FloatAttr>(getValue())) {
3406  return verifyFloatSemantics(floatAttr.getValue().getSemantics(), getType());
3407  } else if (auto elementsAttr = dyn_cast<ElementsAttr>(getValue())) {
3408  if (hasScalableVectorType(getType())) {
3409  // The exact number of elements of a scalable vector is unknown, so we
3410  // allow only splat attributes.
3411  auto splatElementsAttr = dyn_cast<SplatElementsAttr>(getValue());
3412  if (!splatElementsAttr)
3413  return emitOpError()
3414  << "scalable vector type requires a splat attribute";
3415  return success();
3416  }
3417  if (!isa<VectorType, LLVM::LLVMArrayType>(getType()))
3418  return emitOpError() << "expected vector or array type";
3419 
3420  // The number of elements of the attribute and the type must match.
3421  int64_t attrNumElements = elementsAttr.getNumElements();
3422  if (getNumElements(getType()) != attrNumElements) {
3423  return emitOpError()
3424  << "type and attribute have a different number of elements: "
3425  << getNumElements(getType()) << " vs. " << attrNumElements;
3426  }
3427 
3428  Type attrElmType = getElementType(elementsAttr.getType());
3429  Type resultElmType = getElementType(getType());
3430  if (auto floatType = dyn_cast<FloatType>(attrElmType))
3431  return verifyFloatSemantics(floatType.getFloatSemantics(), resultElmType);
3432 
3433  if (isa<IntegerType>(attrElmType) && !isa<IntegerType>(resultElmType)) {
3434  return emitOpError(
3435  "expected integer element type for integer elements attribute");
3436  }
3437  } else if (auto arrayAttr = dyn_cast<ArrayAttr>(getValue())) {
3438 
3439  // The case where the constant is LLVMStructType has already been handled.
3440  auto arrayType = dyn_cast<LLVM::LLVMArrayType>(getType());
3441  if (!arrayType)
3442  return emitOpError()
3443  << "expected array or struct type for array attribute";
3444 
3445  // When the attribute is an ArrayAttr, check that its nesting matches the
3446  // corresponding ArrayType or VectorType nesting.
3447  return verifyStructArrayConstant(*this, arrayType, arrayAttr, /*dim=*/0);
3448  } else {
3449  return emitOpError()
3450  << "only supports integer, float, string or elements attributes";
3451  }
3452 
3453  return success();
3454 }
3455 
3456 bool LLVM::ConstantOp::isBuildableWith(Attribute value, Type type) {
3457  // The value's type must be the same as the provided type.
3458  auto typedAttr = dyn_cast<TypedAttr>(value);
3459  if (!typedAttr || typedAttr.getType() != type || !isCompatibleType(type))
3460  return false;
3461  // The value's type must be an LLVM compatible type.
3462  if (!isCompatibleType(type))
3463  return false;
3464  // TODO: Add support for additional attributes kinds once needed.
3465  return isa<IntegerAttr, FloatAttr, ElementsAttr>(value);
3466 }
3467 
3468 ConstantOp LLVM::ConstantOp::materialize(OpBuilder &builder, Attribute value,
3469  Type type, Location loc) {
3470  if (isBuildableWith(value, type))
3471  return LLVM::ConstantOp::create(builder, loc, cast<TypedAttr>(value));
3472  return nullptr;
3473 }
3474 
3475 // Constant op constant-folds to its value.
3476 OpFoldResult LLVM::ConstantOp::fold(FoldAdaptor) { return getValue(); }
3477 
3478 //===----------------------------------------------------------------------===//
3479 // AtomicRMWOp
3480 //===----------------------------------------------------------------------===//
3481 
3482 void AtomicRMWOp::build(OpBuilder &builder, OperationState &state,
3483  AtomicBinOp binOp, Value ptr, Value val,
3484  AtomicOrdering ordering, StringRef syncscope,
3485  unsigned alignment, bool isVolatile) {
3486  build(builder, state, val.getType(), binOp, ptr, val, ordering,
3487  !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
3488  alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
3489  /*access_groups=*/nullptr,
3490  /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
3491 }
3492 
3493 LogicalResult AtomicRMWOp::verify() {
3494  auto valType = getVal().getType();
3495  if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub ||
3496  getBinOp() == AtomicBinOp::fmin || getBinOp() == AtomicBinOp::fmax ||
3497  getBinOp() == AtomicBinOp::fminimum ||
3498  getBinOp() == AtomicBinOp::fmaximum) {
3499  if (isCompatibleVectorType(valType)) {
3500  if (isScalableVectorType(valType))
3501  return emitOpError("expected LLVM IR fixed vector type");
3502  Type elemType = llvm::cast<VectorType>(valType).getElementType();
3503  if (!isCompatibleFloatingPointType(elemType))
3504  return emitOpError(
3505  "expected LLVM IR floating point type for vector element");
3506  } else if (!isCompatibleFloatingPointType(valType)) {
3507  return emitOpError("expected LLVM IR floating point type");
3508  }
3509  } else if (getBinOp() == AtomicBinOp::xchg) {
3510  DataLayout dataLayout = DataLayout::closest(*this);
3511  if (!isTypeCompatibleWithAtomicOp(valType, dataLayout))
3512  return emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
3513  } else {
3514  auto intType = llvm::dyn_cast<IntegerType>(valType);
3515  unsigned intBitWidth = intType ? intType.getWidth() : 0;
3516  if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
3517  intBitWidth != 64)
3518  return emitOpError("expected LLVM IR integer type");
3519  }
3520 
3521  if (static_cast<unsigned>(getOrdering()) <
3522  static_cast<unsigned>(AtomicOrdering::monotonic))
3523  return emitOpError() << "expected at least '"
3524  << stringifyAtomicOrdering(AtomicOrdering::monotonic)
3525  << "' ordering";
3526 
3527  return success();
3528 }
3529 
3530 //===----------------------------------------------------------------------===//
3531 // AtomicCmpXchgOp
3532 //===----------------------------------------------------------------------===//
3533 
3534 /// Returns an LLVM struct type that contains a value type and a boolean type.
3535 static LLVMStructType getValAndBoolStructType(Type valType) {
3536  auto boolType = IntegerType::get(valType.getContext(), 1);
3537  return LLVMStructType::getLiteral(valType.getContext(), {valType, boolType});
3538 }
3539 
3540 void AtomicCmpXchgOp::build(OpBuilder &builder, OperationState &state,
3541  Value ptr, Value cmp, Value val,
3542  AtomicOrdering successOrdering,
3543  AtomicOrdering failureOrdering, StringRef syncscope,
3544  unsigned alignment, bool isWeak, bool isVolatile) {
3545  build(builder, state, getValAndBoolStructType(val.getType()), ptr, cmp, val,
3546  successOrdering, failureOrdering,
3547  !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
3548  alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isWeak,
3549  isVolatile, /*access_groups=*/nullptr,
3550  /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
3551 }
3552 
3553 LogicalResult AtomicCmpXchgOp::verify() {
3554  auto ptrType = llvm::cast<LLVM::LLVMPointerType>(getPtr().getType());
3555  if (!ptrType)
3556  return emitOpError("expected LLVM IR pointer type for operand #0");
3557  auto valType = getVal().getType();
3558  DataLayout dataLayout = DataLayout::closest(*this);
3559  if (!isTypeCompatibleWithAtomicOp(valType, dataLayout))
3560  return emitOpError("unexpected LLVM IR type");
3561  if (getSuccessOrdering() < AtomicOrdering::monotonic ||
3562  getFailureOrdering() < AtomicOrdering::monotonic)
3563  return emitOpError("ordering must be at least 'monotonic'");
3564  if (getFailureOrdering() == AtomicOrdering::release ||
3565  getFailureOrdering() == AtomicOrdering::acq_rel)
3566  return emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
3567  return success();
3568 }
3569 
3570 //===----------------------------------------------------------------------===//
3571 // FenceOp
3572 //===----------------------------------------------------------------------===//
3573 
3574 void FenceOp::build(OpBuilder &builder, OperationState &state,
3575  AtomicOrdering ordering, StringRef syncscope) {
3576  build(builder, state, ordering,
3577  syncscope.empty() ? nullptr : builder.getStringAttr(syncscope));
3578 }
3579 
3580 LogicalResult FenceOp::verify() {
3581  if (getOrdering() == AtomicOrdering::not_atomic ||
3582  getOrdering() == AtomicOrdering::unordered ||
3583  getOrdering() == AtomicOrdering::monotonic)
3584  return emitOpError("can be given only acquire, release, acq_rel, "
3585  "and seq_cst orderings");
3586  return success();
3587 }
3588 
3589 //===----------------------------------------------------------------------===//
3590 // Verifier for extension ops
3591 //===----------------------------------------------------------------------===//
3592 
3593 /// Verifies that the given extension operation operates on consistent scalars
3594 /// or vectors, and that the target width is larger than the input width.
3595 template <class ExtOp>
3596 static LogicalResult verifyExtOp(ExtOp op) {
3597  IntegerType inputType, outputType;
3598  if (isCompatibleVectorType(op.getArg().getType())) {
3599  if (!isCompatibleVectorType(op.getResult().getType()))
3600  return op.emitError(
3601  "input type is a vector but output type is an integer");
3602  if (getVectorNumElements(op.getArg().getType()) !=
3603  getVectorNumElements(op.getResult().getType()))
3604  return op.emitError("input and output vectors are of incompatible shape");
3605  // Because this is a CastOp, the element of vectors is guaranteed to be an
3606  // integer.
3607  inputType = cast<IntegerType>(
3608  cast<VectorType>(op.getArg().getType()).getElementType());
3609  outputType = cast<IntegerType>(
3610  cast<VectorType>(op.getResult().getType()).getElementType());
3611  } else {
3612  // Because this is a CastOp and arg is not a vector, arg is guaranteed to be
3613  // an integer.
3614  inputType = cast<IntegerType>(op.getArg().getType());
3615  outputType = dyn_cast<IntegerType>(op.getResult().getType());
3616  if (!outputType)
3617  return op.emitError(
3618  "input type is an integer but output type is a vector");
3619  }
3620 
3621  if (outputType.getWidth() <= inputType.getWidth())
3622  return op.emitError("integer width of the output type is smaller or "
3623  "equal to the integer width of the input type");
3624  return success();
3625 }
3626 
3627 //===----------------------------------------------------------------------===//
3628 // ZExtOp
3629 //===----------------------------------------------------------------------===//
3630 
3631 LogicalResult ZExtOp::verify() { return verifyExtOp<ZExtOp>(*this); }
3632 
3633 OpFoldResult LLVM::ZExtOp::fold(FoldAdaptor adaptor) {
3634  auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
3635  if (!arg)
3636  return {};
3637 
3638  size_t targetSize = cast<IntegerType>(getType()).getWidth();
3639  return IntegerAttr::get(getType(), arg.getValue().zext(targetSize));
3640 }
3641 
3642 //===----------------------------------------------------------------------===//
3643 // SExtOp
3644 //===----------------------------------------------------------------------===//
3645 
3646 LogicalResult SExtOp::verify() { return verifyExtOp<SExtOp>(*this); }
3647 
3648 //===----------------------------------------------------------------------===//
3649 // Folder and verifier for LLVM::BitcastOp
3650 //===----------------------------------------------------------------------===//
3651 
3652 /// Folds a cast op that can be chained.
3653 template <typename T>
3655  typename T::FoldAdaptor adaptor) {
3656  // cast(x : T0, T0) -> x
3657  if (castOp.getArg().getType() == castOp.getType())
3658  return castOp.getArg();
3659  if (auto prev = castOp.getArg().template getDefiningOp<T>()) {
3660  // cast(cast(x : T0, T1), T0) -> x
3661  if (prev.getArg().getType() == castOp.getType())
3662  return prev.getArg();
3663  // cast(cast(x : T0, T1), T2) -> cast(x: T0, T2)
3664  castOp.getArgMutable().set(prev.getArg());
3665  return Value{castOp};
3666  }
3667  return {};
3668 }
3669 
3670 OpFoldResult LLVM::BitcastOp::fold(FoldAdaptor adaptor) {
3671  return foldChainableCast(*this, adaptor);
3672 }
3673 
3674 LogicalResult LLVM::BitcastOp::verify() {
3675  auto resultType = llvm::dyn_cast<LLVMPointerType>(
3676  extractVectorElementType(getResult().getType()));
3677  auto sourceType = llvm::dyn_cast<LLVMPointerType>(
3678  extractVectorElementType(getArg().getType()));
3679 
3680  // If one of the types is a pointer (or vector of pointers), then
3681  // both source and result type have to be pointers.
3682  if (static_cast<bool>(resultType) != static_cast<bool>(sourceType))
3683  return emitOpError("can only cast pointers from and to pointers");
3684 
3685  if (!resultType)
3686  return success();
3687 
3688  auto isVector = llvm::IsaPred<VectorType>;
3689 
3690  // Due to bitcast requiring both operands to be of the same size, it is not
3691  // possible for only one of the two to be a pointer of vectors.
3692  if (isVector(getResult().getType()) && !isVector(getArg().getType()))
3693  return emitOpError("cannot cast pointer to vector of pointers");
3694 
3695  if (!isVector(getResult().getType()) && isVector(getArg().getType()))
3696  return emitOpError("cannot cast vector of pointers to pointer");
3697 
3698  // Bitcast cannot cast between pointers of different address spaces.
3699  // 'llvm.addrspacecast' must be used for this purpose instead.
3700  if (resultType.getAddressSpace() != sourceType.getAddressSpace())
3701  return emitOpError("cannot cast pointers of different address spaces, "
3702  "use 'llvm.addrspacecast' instead");
3703 
3704  return success();
3705 }
3706 
3707 //===----------------------------------------------------------------------===//
3708 // Folder for LLVM::AddrSpaceCastOp
3709 //===----------------------------------------------------------------------===//
3710 
3711 OpFoldResult LLVM::AddrSpaceCastOp::fold(FoldAdaptor adaptor) {
3712  return foldChainableCast(*this, adaptor);
3713 }
3714 
3715 Value LLVM::AddrSpaceCastOp::getViewSource() { return getArg(); }
3716 
3717 //===----------------------------------------------------------------------===//
3718 // Folder for LLVM::GEPOp
3719 //===----------------------------------------------------------------------===//
3720 
3721 OpFoldResult LLVM::GEPOp::fold(FoldAdaptor adaptor) {
3722  GEPIndicesAdaptor<ArrayRef<Attribute>> indices(getRawConstantIndicesAttr(),
3723  adaptor.getDynamicIndices());
3724 
3725  // gep %x:T, 0 -> %x
3726  if (getBase().getType() == getType() && indices.size() == 1)
3727  if (auto integer = llvm::dyn_cast_or_null<IntegerAttr>(indices[0]))
3728  if (integer.getValue().isZero())
3729  return getBase();
3730 
3731  // Canonicalize any dynamic indices of constant value to constant indices.
3732  bool changed = false;
3733  SmallVector<GEPArg> gepArgs;
3734  for (auto iter : llvm::enumerate(indices)) {
3735  auto integer = llvm::dyn_cast_or_null<IntegerAttr>(iter.value());
3736  // Constant indices can only be int32_t, so if integer does not fit we
3737  // are forced to keep it dynamic, despite being a constant.
3738  if (!indices.isDynamicIndex(iter.index()) || !integer ||
3739  !integer.getValue().isSignedIntN(kGEPConstantBitWidth)) {
3740 
3741  PointerUnion<IntegerAttr, Value> existing = getIndices()[iter.index()];
3742  if (Value val = llvm::dyn_cast_if_present<Value>(existing))
3743  gepArgs.emplace_back(val);
3744  else
3745  gepArgs.emplace_back(cast<IntegerAttr>(existing).getInt());
3746 
3747  continue;
3748  }
3749 
3750  changed = true;
3751  gepArgs.emplace_back(integer.getInt());
3752  }
3753  if (changed) {
3754  SmallVector<int32_t> rawConstantIndices;
3755  SmallVector<Value> dynamicIndices;
3756  destructureIndices(getElemType(), gepArgs, rawConstantIndices,
3757  dynamicIndices);
3758 
3759  getDynamicIndicesMutable().assign(dynamicIndices);
3760  setRawConstantIndices(rawConstantIndices);
3761  return Value{*this};
3762  }
3763 
3764  return {};
3765 }
3766 
3767 Value LLVM::GEPOp::getViewSource() { return getBase(); }
3768 
3769 //===----------------------------------------------------------------------===//
3770 // ShlOp
3771 //===----------------------------------------------------------------------===//
3772 
3773 OpFoldResult LLVM::ShlOp::fold(FoldAdaptor adaptor) {
3774  auto rhs = dyn_cast_or_null<IntegerAttr>(adaptor.getRhs());
3775  if (!rhs)
3776  return {};
3777 
3778  if (rhs.getValue().getZExtValue() >=
3779  getLhs().getType().getIntOrFloatBitWidth())
3780  return {}; // TODO: Fold into poison.
3781 
3782  auto lhs = dyn_cast_or_null<IntegerAttr>(adaptor.getLhs());
3783  if (!lhs)
3784  return {};
3785 
3786  return IntegerAttr::get(getType(), lhs.getValue().shl(rhs.getValue()));
3787 }
3788 
3789 //===----------------------------------------------------------------------===//
3790 // OrOp
3791 //===----------------------------------------------------------------------===//
3792 
3793 OpFoldResult LLVM::OrOp::fold(FoldAdaptor adaptor) {
3794  auto lhs = dyn_cast_or_null<IntegerAttr>(adaptor.getLhs());
3795  if (!lhs)
3796  return {};
3797 
3798  auto rhs = dyn_cast_or_null<IntegerAttr>(adaptor.getRhs());
3799  if (!rhs)
3800  return {};
3801 
3802  return IntegerAttr::get(getType(), lhs.getValue() | rhs.getValue());
3803 }
3804 
3805 //===----------------------------------------------------------------------===//
3806 // CallIntrinsicOp
3807 //===----------------------------------------------------------------------===//
3808 
3809 LogicalResult CallIntrinsicOp::verify() {
3810  if (!getIntrin().starts_with("llvm."))
3811  return emitOpError() << "intrinsic name must start with 'llvm.'";
3812  if (failed(verifyOperandBundles(*this)))
3813  return failure();
3814  return success();
3815 }
3816 
3817 void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state,
3818  mlir::StringAttr intrin, mlir::ValueRange args) {
3819  build(builder, state, /*resultTypes=*/TypeRange{}, intrin, args,
3820  FastmathFlagsAttr{},
3821  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{},
3822  /*res_attrs=*/{});
3823 }
3824 
3825 void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state,
3826  mlir::StringAttr intrin, mlir::ValueRange args,
3827  mlir::LLVM::FastmathFlagsAttr fastMathFlags) {
3828  build(builder, state, /*resultTypes=*/TypeRange{}, intrin, args,
3829  fastMathFlags,
3830  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{},
3831  /*res_attrs=*/{});
3832 }
3833 
3834 void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state,
3835  mlir::Type resultType, mlir::StringAttr intrin,
3836  mlir::ValueRange args) {
3837  build(builder, state, {resultType}, intrin, args, FastmathFlagsAttr{},
3838  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{},
3839  /*res_attrs=*/{});
3840 }
3841 
3842 void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state,
3843  mlir::TypeRange resultTypes,
3844  mlir::StringAttr intrin, mlir::ValueRange args,
3845  mlir::LLVM::FastmathFlagsAttr fastMathFlags) {
3846  build(builder, state, resultTypes, intrin, args, fastMathFlags,
3847  /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{},
3848  /*res_attrs=*/{});
3849 }
3850 
3851 ParseResult CallIntrinsicOp::parse(OpAsmParser &parser,
3852  OperationState &result) {
3853  StringAttr intrinAttr;
3856  SmallVector<SmallVector<Type>> opBundleOperandTypes;
3857  ArrayAttr opBundleTags;
3858 
3859  // Parse intrinsic name.
3861  intrinAttr, parser.getBuilder().getType<NoneType>()))
3862  return failure();
3863  result.addAttribute(CallIntrinsicOp::getIntrinAttrName(result.name),
3864  intrinAttr);
3865 
3866  if (parser.parseLParen())
3867  return failure();
3868 
3869  // Parse the function arguments.
3870  if (parser.parseOperandList(operands))
3871  return mlir::failure();
3872 
3873  if (parser.parseRParen())
3874  return mlir::failure();
3875 
3876  // Handle bundles.
3877  SMLoc opBundlesLoc = parser.getCurrentLocation();
3878  if (std::optional<ParseResult> result = parseOpBundles(
3879  parser, opBundleOperands, opBundleOperandTypes, opBundleTags);
3880  result && failed(*result))
3881  return failure();
3882  if (opBundleTags && !opBundleTags.empty())
3883  result.addAttribute(
3884  CallIntrinsicOp::getOpBundleTagsAttrName(result.name).getValue(),
3885  opBundleTags);
3886 
3887  if (parser.parseOptionalAttrDict(result.attributes))
3888  return mlir::failure();
3889 
3890  SmallVector<DictionaryAttr> argAttrs;
3891  SmallVector<DictionaryAttr> resultAttrs;
3892  if (parseCallTypeAndResolveOperands(parser, result, /*isDirect=*/true,
3893  operands, argAttrs, resultAttrs))
3894  return failure();
3896  parser.getBuilder(), result, argAttrs, resultAttrs,
3897  getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
3898 
3899  if (resolveOpBundleOperands(parser, opBundlesLoc, result, opBundleOperands,
3900  opBundleOperandTypes,
3901  getOpBundleSizesAttrName(result.name)))
3902  return failure();
3903 
3904  int32_t numOpBundleOperands = 0;
3905  for (const auto &operands : opBundleOperands)
3906  numOpBundleOperands += operands.size();
3907 
3908  result.addAttribute(
3909  CallIntrinsicOp::getOperandSegmentSizeAttr(),
3911  {static_cast<int32_t>(operands.size()), numOpBundleOperands}));
3912 
3913  return mlir::success();
3914 }
3915 
3917  p << ' ';
3918  p.printAttributeWithoutType(getIntrinAttr());
3919 
3920  OperandRange args = getArgs();
3921  p << "(" << args << ")";
3922 
3923  // Operand bundles.
3924  if (!getOpBundleOperands().empty()) {
3925  p << ' ';
3926  printOpBundles(p, *this, getOpBundleOperands(),
3927  getOpBundleOperands().getTypes(), getOpBundleTagsAttr());
3928  }
3929 
3930  p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()),
3931  {getOperandSegmentSizesAttrName(),
3932  getOpBundleSizesAttrName(), getIntrinAttrName(),
3933  getOpBundleTagsAttrName(), getArgAttrsAttrName(),
3934  getResAttrsAttrName()});
3935 
3936  p << " : ";
3937 
3938  // Reconstruct the MLIR function type from operand and result types.
3940  p, args.getTypes(), getArgAttrsAttr(),
3941  /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());
3942 }
3943 
3944 //===----------------------------------------------------------------------===//
3945 // LinkerOptionsOp
3946 //===----------------------------------------------------------------------===//
3947 
3948 LogicalResult LinkerOptionsOp::verify() {
3949  if (mlir::Operation *parentOp = (*this)->getParentOp();
3950  parentOp && !satisfiesLLVMModule(parentOp))
3951  return emitOpError("must appear at the module level");
3952  return success();
3953 }
3954 
3955 //===----------------------------------------------------------------------===//
3956 // ModuleFlagsOp
3957 //===----------------------------------------------------------------------===//
3958 
3959 LogicalResult ModuleFlagsOp::verify() {
3960  if (Operation *parentOp = (*this)->getParentOp();
3961  parentOp && !satisfiesLLVMModule(parentOp))
3962  return emitOpError("must appear at the module level");
3963  for (Attribute flag : getFlags())
3964  if (!isa<ModuleFlagAttr>(flag))
3965  return emitOpError("expected a module flag attribute");
3966  return success();
3967 }
3968 
3969 //===----------------------------------------------------------------------===//
3970 // InlineAsmOp
3971 //===----------------------------------------------------------------------===//
3972 
3973 void InlineAsmOp::getEffects(
3975  &effects) {
3976  if (getHasSideEffects()) {
3977  effects.emplace_back(MemoryEffects::Write::get());
3978  effects.emplace_back(MemoryEffects::Read::get());
3979  }
3980 }
3981 
3982 //===----------------------------------------------------------------------===//
3983 // BlockAddressOp
3984 //===----------------------------------------------------------------------===//
3985 
3986 LogicalResult
3987 BlockAddressOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3988  Operation *symbol = symbolTable.lookupSymbolIn(parentLLVMModule(*this),
3989  getBlockAddr().getFunction());
3990  auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
3991 
3992  if (!function)
3993  return emitOpError("must reference a function defined by 'llvm.func'");
3994 
3995  return success();
3996 }
3997 
3998 LLVMFuncOp BlockAddressOp::getFunction(SymbolTableCollection &symbolTable) {
3999  return dyn_cast_or_null<LLVMFuncOp>(symbolTable.lookupSymbolIn(
4000  parentLLVMModule(*this), getBlockAddr().getFunction()));
4001 }
4002 
4003 BlockTagOp BlockAddressOp::getBlockTagOp() {
4004  auto funcOp = dyn_cast<LLVMFuncOp>(mlir::SymbolTable::lookupNearestSymbolFrom(
4005  parentLLVMModule(*this), getBlockAddr().getFunction()));
4006  if (!funcOp)
4007  return nullptr;
4008 
4009  BlockTagOp blockTagOp = nullptr;
4010  funcOp.walk([&](LLVM::BlockTagOp labelOp) {
4011  if (labelOp.getTag() == getBlockAddr().getTag()) {
4012  blockTagOp = labelOp;
4013  return WalkResult::interrupt();
4014  }
4015  return WalkResult::advance();
4016  });
4017  return blockTagOp;
4018 }
4019 
4020 LogicalResult BlockAddressOp::verify() {
4021  if (!getBlockTagOp())
4022  return emitOpError(
4023  "expects an existing block label target in the referenced function");
4024 
4025  return success();
4026 }
4027 
4028 /// Fold a blockaddress operation to a dedicated blockaddress
4029 /// attribute.
4030 OpFoldResult BlockAddressOp::fold(FoldAdaptor) { return getBlockAddr(); }
4031 
4032 //===----------------------------------------------------------------------===//
4033 // LLVM::IndirectBrOp
4034 //===----------------------------------------------------------------------===//
4035 
4037  assert(index < getNumSuccessors() && "invalid successor index");
4038  return SuccessorOperands(getSuccOperandsMutable()[index]);
4039 }
4040 
4041 void IndirectBrOp::build(OpBuilder &odsBuilder, OperationState &odsState,
4042  Value addr, ArrayRef<ValueRange> succOperands,
4043  BlockRange successors) {
4044  odsState.addOperands(addr);
4045  for (ValueRange range : succOperands)
4046  odsState.addOperands(range);
4047  SmallVector<int32_t> rangeSegments;
4048  for (ValueRange range : succOperands)
4049  rangeSegments.push_back(range.size());
4050  odsState.getOrAddProperties<Properties>().indbr_operand_segments =
4051  odsBuilder.getDenseI32ArrayAttr(rangeSegments);
4052  odsState.addSuccessors(successors);
4053 }
4054 
4055 static ParseResult parseIndirectBrOpSucessors(
4056  OpAsmParser &parser, Type &flagType,
4057  SmallVectorImpl<Block *> &succOperandBlocks,
4059  SmallVectorImpl<SmallVector<Type>> &succOperandsTypes) {
4060  if (failed(parser.parseCommaSeparatedList(
4062  [&]() {
4063  Block *destination = nullptr;
4064  SmallVector<OpAsmParser::UnresolvedOperand> operands;
4065  SmallVector<Type> operandTypes;
4066 
4067  if (parser.parseSuccessor(destination).failed())
4068  return failure();
4069 
4070  if (succeeded(parser.parseOptionalLParen())) {
4071  if (failed(parser.parseOperandList(
4072  operands, OpAsmParser::Delimiter::None)) ||
4073  failed(parser.parseColonTypeList(operandTypes)) ||
4074  failed(parser.parseRParen()))
4075  return failure();
4076  }
4077  succOperandBlocks.push_back(destination);
4078  succOperands.emplace_back(operands);
4079  succOperandsTypes.emplace_back(operandTypes);
4080  return success();
4081  },
4082  "successor blocks")))
4083  return failure();
4084  return success();
4085 }
4086 
4087 static void
4088 printIndirectBrOpSucessors(OpAsmPrinter &p, IndirectBrOp op, Type flagType,
4089  SuccessorRange succs, OperandRangeRange succOperands,
4090  const TypeRangeRange &succOperandsTypes) {
4091  p << "[";
4092  llvm::interleave(
4093  llvm::zip(succs, succOperands),
4094  [&](auto i) {
4095  p.printNewline();
4096  p.printSuccessorAndUseList(std::get<0>(i), std::get<1>(i));
4097  },
4098  [&] { p << ','; });
4099  if (!succOperands.empty())
4100  p.printNewline();
4101  p << "]";
4102 }
4103 
4104 //===----------------------------------------------------------------------===//
4105 // SincosOp (intrinsic)
4106 //===----------------------------------------------------------------------===//
4107 
4108 LogicalResult LLVM::SincosOp::verify() {
4109  auto operandType = getOperand().getType();
4110  auto resultType = getResult().getType();
4111  auto resultStructType =
4112  mlir::dyn_cast<mlir::LLVM::LLVMStructType>(resultType);
4113  if (!resultStructType || resultStructType.getBody().size() != 2 ||
4114  resultStructType.getBody()[0] != operandType ||
4115  resultStructType.getBody()[1] != operandType) {
4116  return emitOpError("expected result type to be an homogeneous struct with "
4117  "two elements matching the operand type, but got ")
4118  << resultType;
4119  }
4120  return success();
4121 }
4122 
4123 //===----------------------------------------------------------------------===//
4124 // AssumeOp (intrinsic)
4125 //===----------------------------------------------------------------------===//
4126 
4127 void LLVM::AssumeOp::build(OpBuilder &builder, OperationState &state,
4128  mlir::Value cond) {
4129  return build(builder, state, cond, /*op_bundle_operands=*/{},
4130  /*op_bundle_tags=*/ArrayAttr{});
4131 }
4132 
4133 void LLVM::AssumeOp::build(OpBuilder &builder, OperationState &state,
4134  Value cond, llvm::StringRef tag, ValueRange args) {
4135  return build(builder, state, cond, ArrayRef<ValueRange>(args),
4136  builder.getStrArrayAttr(tag));
4137 }
4138 
4139 void LLVM::AssumeOp::build(OpBuilder &builder, OperationState &state,
4140  Value cond, AssumeAlignTag, Value ptr, Value align) {
4141  return build(builder, state, cond, "align", ValueRange{ptr, align});
4142 }
4143 
4144 void LLVM::AssumeOp::build(OpBuilder &builder, OperationState &state,
4145  Value cond, AssumeSeparateStorageTag, Value ptr1,
4146  Value ptr2) {
4147  return build(builder, state, cond, "separate_storage",
4148  ValueRange{ptr1, ptr2});
4149 }
4150 
4151 LogicalResult LLVM::AssumeOp::verify() { return verifyOperandBundles(*this); }
4152 
4153 //===----------------------------------------------------------------------===//
4154 // masked_gather (intrinsic)
4155 //===----------------------------------------------------------------------===//
4156 
4157 LogicalResult LLVM::masked_gather::verify() {
4158  auto ptrsVectorType = getPtrs().getType();
4159  Type expectedPtrsVectorType =
4161  LLVM::getVectorNumElements(getRes().getType()));
4162  // Vector of pointers type should match result vector type, other than the
4163  // element type.
4164  if (ptrsVectorType != expectedPtrsVectorType)
4165  return emitOpError("expected operand #1 type to be ")
4166  << expectedPtrsVectorType;
4167  return success();
4168 }
4169 
4170 //===----------------------------------------------------------------------===//
4171 // masked_scatter (intrinsic)
4172 //===----------------------------------------------------------------------===//
4173 
4174 LogicalResult LLVM::masked_scatter::verify() {
4175  auto ptrsVectorType = getPtrs().getType();
4176  Type expectedPtrsVectorType =
4178  LLVM::getVectorNumElements(getValue().getType()));
4179  // Vector of pointers type should match value vector type, other than the
4180  // element type.
4181  if (ptrsVectorType != expectedPtrsVectorType)
4182  return emitOpError("expected operand #2 type to be ")
4183  << expectedPtrsVectorType;
4184  return success();
4185 }
4186 
4187 //===----------------------------------------------------------------------===//
4188 // masked_expandload (intrinsic)
4189 //===----------------------------------------------------------------------===//
4190 
4191 void LLVM::masked_expandload::build(OpBuilder &builder, OperationState &state,
4192  mlir::TypeRange resTys, Value ptr,
4193  Value mask, Value passthru,
4194  uint64_t align) {
4195  ArrayAttr argAttrs = getLLVMAlignParamForCompressExpand(builder, true, align);
4196  build(builder, state, resTys, ptr, mask, passthru, /*arg_attrs=*/argAttrs,
4197  /*res_attrs=*/nullptr);
4198 }
4199 
4200 //===----------------------------------------------------------------------===//
4201 // masked_compressstore (intrinsic)
4202 //===----------------------------------------------------------------------===//
4203 
4204 void LLVM::masked_compressstore::build(OpBuilder &builder,
4205  OperationState &state, Value value,
4206  Value ptr, Value mask, uint64_t align) {
4207  ArrayAttr argAttrs =
4208  getLLVMAlignParamForCompressExpand(builder, false, align);
4209  build(builder, state, value, ptr, mask, /*arg_attrs=*/argAttrs,
4210  /*res_attrs=*/nullptr);
4211 }
4212 
4213 //===----------------------------------------------------------------------===//
4214 // InlineAsmOp
4215 //===----------------------------------------------------------------------===//
4216 
4217 LogicalResult InlineAsmOp::verify() {
4218  if (!getTailCallKindAttr())
4219  return success();
4220 
4221  if (getTailCallKindAttr().getTailCallKind() == TailCallKind::MustTail)
4222  return emitOpError(
4223  "tail call kind 'musttail' is not supported by this operation");
4224 
4225  return success();
4226 }
4227 
4228 //===----------------------------------------------------------------------===//
4229 // LLVMDialect initialization, type parsing, and registration.
4230 //===----------------------------------------------------------------------===//
4231 
4232 void LLVMDialect::initialize() {
4233  registerAttributes();
4234 
4235  // clang-format off
4236  addTypes<LLVMVoidType,
4237  LLVMTokenType,
4238  LLVMLabelType,
4239  LLVMMetadataType>();
4240  // clang-format on
4241  registerTypes();
4242 
4243  addOperations<
4244 #define GET_OP_LIST
4245 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
4246 
4247  ,
4248 #define GET_OP_LIST
4249 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicOps.cpp.inc"
4250 
4251  >();
4252 
4253  // Support unknown operations because not all LLVM operations are registered.
4254  allowUnknownOperations();
4255  declarePromisedInterface<DialectInlinerInterface, LLVMDialect>();
4257 }
4258 
4259 #define GET_OP_CLASSES
4260 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
4261 
4262 #define GET_OP_CLASSES
4263 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicOps.cpp.inc"
4264 
4265 LogicalResult LLVMDialect::verifyDataLayoutString(
4266  StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
4267  llvm::Expected<llvm::DataLayout> maybeDataLayout =
4268  llvm::DataLayout::parse(descr);
4269  if (maybeDataLayout)
4270  return success();
4271 
4272  std::string message;
4273  llvm::raw_string_ostream messageStream(message);
4274  llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
4275  reportError("invalid data layout descriptor: " + message);
4276  return failure();
4277 }
4278 
4279 /// Verify LLVM dialect attributes.
4280 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
4281  NamedAttribute attr) {
4282  // If the data layout attribute is present, it must use the LLVM data layout
4283  // syntax. Try parsing it and report errors in case of failure. Users of this
4284  // attribute may assume it is well-formed and can pass it to the (asserting)
4285  // llvm::DataLayout constructor.
4286  if (attr.getName() != LLVM::LLVMDialect::getDataLayoutAttrName())
4287  return success();
4288  if (auto stringAttr = llvm::dyn_cast<StringAttr>(attr.getValue()))
4289  return verifyDataLayoutString(
4290  stringAttr.getValue(),
4291  [op](const Twine &message) { op->emitOpError() << message.str(); });
4292 
4293  return op->emitOpError() << "expected '"
4294  << LLVM::LLVMDialect::getDataLayoutAttrName()
4295  << "' to be a string attributes";
4296 }
4297 
4298 LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op,
4299  Type paramType,
4300  NamedAttribute paramAttr) {
4301  // LLVM attribute may be attached to a result of operation that has not been
4302  // converted to LLVM dialect yet, so the result may have a type with unknown
4303  // representation in LLVM dialect type space. In this case we cannot verify
4304  // whether the attribute may be
4305  bool verifyValueType = isCompatibleType(paramType);
4306  StringAttr name = paramAttr.getName();
4307 
4308  auto checkUnitAttrType = [&]() -> LogicalResult {
4309  if (!llvm::isa<UnitAttr>(paramAttr.getValue()))
4310  return op->emitError() << name << " should be a unit attribute";
4311  return success();
4312  };
4313  auto checkTypeAttrType = [&]() -> LogicalResult {
4314  if (!llvm::isa<TypeAttr>(paramAttr.getValue()))
4315  return op->emitError() << name << " should be a type attribute";
4316  return success();
4317  };
4318  auto checkIntegerAttrType = [&]() -> LogicalResult {
4319  if (!llvm::isa<IntegerAttr>(paramAttr.getValue()))
4320  return op->emitError() << name << " should be an integer attribute";
4321  return success();
4322  };
4323  auto checkPointerType = [&]() -> LogicalResult {
4324  if (!llvm::isa<LLVMPointerType>(paramType))
4325  return op->emitError()
4326  << name << " attribute attached to non-pointer LLVM type";
4327  return success();
4328  };
4329  auto checkIntegerType = [&]() -> LogicalResult {
4330  if (!llvm::isa<IntegerType>(paramType))
4331  return op->emitError()
4332  << name << " attribute attached to non-integer LLVM type";
4333  return success();
4334  };
4335  auto checkPointerTypeMatches = [&]() -> LogicalResult {
4336  if (failed(checkPointerType()))
4337  return failure();
4338 
4339  return success();
4340  };
4341 
4342  // Check a unit attribute that is attached to a pointer value.
4343  if (name == LLVMDialect::getNoAliasAttrName() ||
4344  name == LLVMDialect::getReadonlyAttrName() ||
4345  name == LLVMDialect::getReadnoneAttrName() ||
4346  name == LLVMDialect::getWriteOnlyAttrName() ||
4347  name == LLVMDialect::getNestAttrName() ||
4348  name == LLVMDialect::getNoCaptureAttrName() ||
4349  name == LLVMDialect::getNoFreeAttrName() ||
4350  name == LLVMDialect::getNonNullAttrName()) {
4351  if (failed(checkUnitAttrType()))
4352  return failure();
4353  if (verifyValueType && failed(checkPointerType()))
4354  return failure();
4355  return success();
4356  }
4357 
4358  // Check a type attribute that is attached to a pointer value.
4359  if (name == LLVMDialect::getStructRetAttrName() ||
4360  name == LLVMDialect::getByValAttrName() ||
4361  name == LLVMDialect::getByRefAttrName() ||
4362  name == LLVMDialect::getElementTypeAttrName() ||
4363  name == LLVMDialect::getInAllocaAttrName() ||
4364  name == LLVMDialect::getPreallocatedAttrName()) {
4365  if (failed(checkTypeAttrType()))
4366  return failure();
4367  if (verifyValueType && failed(checkPointerTypeMatches()))
4368  return failure();
4369  return success();
4370  }
4371 
4372  // Check a unit attribute that is attached to an integer value.
4373  if (name == LLVMDialect::getSExtAttrName() ||
4374  name == LLVMDialect::getZExtAttrName()) {
4375  if (failed(checkUnitAttrType()))
4376  return failure();
4377  if (verifyValueType && failed(checkIntegerType()))
4378  return failure();
4379  return success();
4380  }
4381 
4382  // Check an integer attribute that is attached to a pointer value.
4383  if (name == LLVMDialect::getAlignAttrName() ||
4384  name == LLVMDialect::getDereferenceableAttrName() ||
4385  name == LLVMDialect::getDereferenceableOrNullAttrName()) {
4386  if (failed(checkIntegerAttrType()))
4387  return failure();
4388  if (verifyValueType && failed(checkPointerType()))
4389  return failure();
4390  return success();
4391  }
4392 
4393  // Check an integer attribute that is attached to a pointer value.
4394  if (name == LLVMDialect::getStackAlignmentAttrName()) {
4395  if (failed(checkIntegerAttrType()))
4396  return failure();
4397  return success();
4398  }
4399 
4400  // Check a unit attribute that can be attached to arbitrary types.
4401  if (name == LLVMDialect::getNoUndefAttrName() ||
4402  name == LLVMDialect::getInRegAttrName() ||
4403  name == LLVMDialect::getReturnedAttrName())
4404  return checkUnitAttrType();
4405 
4406  return success();
4407 }
4408 
4409 /// Verify LLVMIR function argument attributes.
4410 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
4411  unsigned regionIdx,
4412  unsigned argIdx,
4413  NamedAttribute argAttr) {
4414  auto funcOp = dyn_cast<FunctionOpInterface>(op);
4415  if (!funcOp)
4416  return success();
4417  Type argType = funcOp.getArgumentTypes()[argIdx];
4418 
4419  return verifyParameterAttribute(op, argType, argAttr);
4420 }
4421 
4422 LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op,
4423  unsigned regionIdx,
4424  unsigned resIdx,
4425  NamedAttribute resAttr) {
4426  auto funcOp = dyn_cast<FunctionOpInterface>(op);
4427  if (!funcOp)
4428  return success();
4429  Type resType = funcOp.getResultTypes()[resIdx];
4430 
4431  // Check to see if this function has a void return with a result attribute
4432  // to it. It isn't clear what semantics we would assign to that.
4433  if (llvm::isa<LLVMVoidType>(resType))
4434  return op->emitError() << "cannot attach result attributes to functions "
4435  "with a void return";
4436 
4437  // Check to see if this attribute is allowed as a result attribute. Only
4438  // explicitly forbidden LLVM attributes will cause an error.
4439  auto name = resAttr.getName();
4440  if (name == LLVMDialect::getAllocAlignAttrName() ||
4441  name == LLVMDialect::getAllocatedPointerAttrName() ||
4442  name == LLVMDialect::getByValAttrName() ||
4443  name == LLVMDialect::getByRefAttrName() ||
4444  name == LLVMDialect::getInAllocaAttrName() ||
4445  name == LLVMDialect::getNestAttrName() ||
4446  name == LLVMDialect::getNoCaptureAttrName() ||
4447  name == LLVMDialect::getNoFreeAttrName() ||
4448  name == LLVMDialect::getPreallocatedAttrName() ||
4449  name == LLVMDialect::getReadnoneAttrName() ||
4450  name == LLVMDialect::getReadonlyAttrName() ||
4451  name == LLVMDialect::getReturnedAttrName() ||
4452  name == LLVMDialect::getStackAlignmentAttrName() ||
4453  name == LLVMDialect::getStructRetAttrName() ||
4454  name == LLVMDialect::getWriteOnlyAttrName())
4455  return op->emitError() << name << " is not a valid result attribute";
4456  return verifyParameterAttribute(op, resType, resAttr);
4457 }
4458 
4460  Type type, Location loc) {
4461  // If this was folded from an operation other than llvm.mlir.constant, it
4462  // should be materialized as such. Note that an llvm.mlir.zero may fold into
4463  // a builtin zero attribute and thus will materialize as a llvm.mlir.constant.
4464  if (auto symbol = dyn_cast<FlatSymbolRefAttr>(value))
4465  if (isa<LLVM::LLVMPointerType>(type))
4466  return LLVM::AddressOfOp::create(builder, loc, type, symbol);
4467  if (isa<LLVM::UndefAttr>(value))
4468  return LLVM::UndefOp::create(builder, loc, type);
4469  if (isa<LLVM::PoisonAttr>(value))
4470  return LLVM::PoisonOp::create(builder, loc, type);
4471  if (isa<LLVM::ZeroAttr>(value))
4472  return LLVM::ZeroOp::create(builder, loc, type);
4473  // Otherwise try materializing it as a regular llvm.mlir.constant op.
4474  return LLVM::ConstantOp::materialize(builder, value, type, loc);
4475 }
4476 
4477 //===----------------------------------------------------------------------===//
4478 // Utility functions.
4479 //===----------------------------------------------------------------------===//
4480 
4482  StringRef name, StringRef value,
4483  LLVM::Linkage linkage) {
4484  assert(builder.getInsertionBlock() &&
4485  builder.getInsertionBlock()->getParentOp() &&
4486  "expected builder to point to a block constrained in an op");
4487  auto module =
4488  builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>();
4489  assert(module && "builder points to an op outside of a module");
4490 
4491  // Create the global at the entry of the module.
4492  OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener());
4493  MLIRContext *ctx = builder.getContext();
4494  auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size());
4495  auto global = LLVM::GlobalOp::create(
4496  moduleBuilder, loc, type, /*isConstant=*/true, linkage, name,
4497  builder.getStringAttr(value), /*alignment=*/0);
4498 
4499  LLVMPointerType ptrType = LLVMPointerType::get(ctx);
4500  // Get the pointer to the first character in the global string.
4501  Value globalPtr =
4502  LLVM::AddressOfOp::create(builder, loc, ptrType, global.getSymNameAttr());
4503  return LLVM::GEPOp::create(builder, loc, ptrType, type, globalPtr,
4504  ArrayRef<GEPArg>{0, 0});
4505 }
4506 
4508  return op->hasTrait<OpTrait::SymbolTable>() &&
4510 }
4511 
4513  Operation *module = op->getParentOp();
4514  while (module && !satisfiesLLVMModule(module))
4515  module = module->getParentOp();
4516  assert(module && "unexpected operation outside of a module");
4517  return module;
4518 }
static OperandRange getSuccessorOperands(Block *block, unsigned successorIndex)
Return the operand range used to transfer operands from block to its successor with the given index.
Definition: CFGToSCF.cpp:140
static Value getBase(Value v)
Looks through known "view-like" ops to find the base memref.
static Operation * materializeConstant(Dialect *dialect, OpBuilder &builder, Attribute value, Type type, Location loc)
A utility function used to materialize a constant for a given attribute and type.
Definition: FoldUtils.cpp:51
static MLIRContext * getContext(OpFoldResult val)
static int parseOptionalKeywordAlternative(OpAsmParser &parser, ArrayRef< StringRef > keywords)
Definition: LLVMDialect.cpp:92
static ArrayAttr getLLVMAlignParamForCompressExpand(OpBuilder &builder, bool isExpandLoad, uint64_t alignment=1)
static LogicalResult verifyAtomicMemOp(OpTy memOp, Type valueType, ArrayRef< AtomicOrdering > unsupportedOrderings)
Verifies the attributes and the type of atomic memory access operations.
static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser, EnumTy defaultValue)
Parse an enum from the keyword, or default to the provided default value.
static LogicalResult checkGlobalXtorData(Operation *op, ArrayAttr data)
static ParseResult parseGEPIndices(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &indices, DenseI32ArrayAttr &rawConstantIndices)
static LogicalResult verifyOperandBundles(OpType &op)
static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result)
static void printOneOpBundle(OpAsmPrinter &p, OperandRange operands, TypeRange operandTypes, StringRef tag)
static LogicalResult verifyComdat(Operation *op, std::optional< SymbolRefAttr > attr)
static LLVMFunctionType getLLVMFuncType(MLIRContext *context, TypeRange results, ValueRange args)
Constructs a LLVMFunctionType from MLIR results and args.
static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op, Type flagType, DenseIntElementsAttr caseValues, SuccessorRange caseDestinations, OperandRangeRange caseOperands, const TypeRangeRange &caseOperandTypes)
static ParseResult resolveOpBundleOperands(OpAsmParser &parser, SMLoc loc, OperationState &state, ArrayRef< SmallVector< OpAsmParser::UnresolvedOperand >> opBundleOperands, ArrayRef< SmallVector< Type >> opBundleOperandTypes, StringAttr opBundleSizesAttrName)
static LogicalResult verifyCallOpVarCalleeType(OpTy callOp)
Verify that the parameter and return types of the variadic callee type match the callOp argument and ...
static ParseResult parseOptionalCallFuncPtr(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands)
Parses an optional function pointer operand before the call argument list for indirect calls,...
static bool isZeroAttribute(Attribute value)
static void printGEPIndices(OpAsmPrinter &printer, LLVM::GEPOp gepOp, OperandRange indices, DenseI32ArrayAttr rawConstantIndices)
static LLVMStructType getValAndBoolStructType(Type valType)
Returns an LLVM struct type that contains a value type and a boolean type.
static void printOpBundles(OpAsmPrinter &p, Operation *op, OperandRangeRange opBundleOperands, TypeRangeRange opBundleOperandTypes, std::optional< ArrayAttr > opBundleTags)
static void printShuffleType(AsmPrinter &printer, Operation *op, Type v1Type, Type resType, DenseI32ArrayAttr mask)
Nothing to do when the result type is inferred.
static LogicalResult verifyBlockTags(LLVMFuncOp funcOp)
static Type buildLLVMFunctionType(OpAsmParser &parser, SMLoc loc, ArrayRef< Type > inputs, ArrayRef< Type > outputs, function_interface_impl::VariadicFlag variadicFlag)
static auto processFMFAttr(ArrayRef< NamedAttribute > attrs)
Definition: LLVMDialect.cpp:51
static std::optional< ParseResult > parseOpBundles(OpAsmParser &p, SmallVector< SmallVector< OpAsmParser::UnresolvedOperand >> &opBundleOperands, SmallVector< SmallVector< Type >> &opBundleOperandTypes, ArrayAttr &opBundleTags)
static ParseResult parseSwitchOpCases(OpAsmParser &parser, Type flagType, DenseIntElementsAttr &caseValues, SmallVectorImpl< Block * > &caseDestinations, SmallVectorImpl< SmallVector< OpAsmParser::UnresolvedOperand >> &caseOperands, SmallVectorImpl< SmallVector< Type >> &caseOperandTypes)
<cases> ::= [ (case (, case )* )? ] <case> ::= integer : bb-id (( ssa-use-and-type-list ))?
static TypeAttr getCallOpVarCalleeType(LLVMFunctionType calleeType)
Gets the variadic callee type for a LLVMFunctionType.
static Type getInsertExtractValueElementType(function_ref< InFlightDiagnostic(StringRef)> emitError, Type containerType, ArrayRef< int64_t > position)
Extract the type at position in the LLVM IR aggregate type containerType.
static Type getElementType(Type type)
Determine the element type of type.
static ParseResult parseOneOpBundle(OpAsmParser &p, SmallVector< SmallVector< OpAsmParser::UnresolvedOperand >> &opBundleOperands, SmallVector< SmallVector< Type >> &opBundleOperandTypes, SmallVector< Attribute > &opBundleTags)
static ParseResult parseIndirectBrOpSucessors(OpAsmParser &parser, Type &flagType, SmallVectorImpl< Block * > &succOperandBlocks, SmallVectorImpl< SmallVector< OpAsmParser::UnresolvedOperand >> &succOperands, SmallVectorImpl< SmallVector< Type >> &succOperandsTypes)
static void printIndirectBrOpSucessors(OpAsmPrinter &p, IndirectBrOp op, Type flagType, SuccessorRange succs, OperandRangeRange succOperands, const TypeRangeRange &succOperandsTypes)
static void printLLVMLinkage(OpAsmPrinter &p, Operation *, LinkageAttr val)
static LogicalResult verifyStructArrayConstant(LLVM::ConstantOp op, LLVM::LLVMArrayType arrayType, ArrayAttr arrayAttr, int dim)
Verifies the constant array represented by arrayAttr matches the provided arrayType.
static ParseResult parseCallTypeAndResolveOperands(OpAsmParser &parser, OperationState &result, bool isDirect, ArrayRef< OpAsmParser::UnresolvedOperand > operands, SmallVectorImpl< DictionaryAttr > &argAttrs, SmallVectorImpl< DictionaryAttr > &resultAttrs)
Parses the type of a call operation and resolves the operands if the parsing succeeds.
static LogicalResult verifySymbolAttrUse(FlatSymbolRefAttr symbol, Operation *op, SymbolTableCollection &symbolTable)
Verifies symbol's use in op to ensure the symbol is a valid and fully defined llvm....
Definition: LLVMDialect.cpp:66
static Type extractVectorElementType(Type type)
Returns the elemental type of any LLVM-compatible vector type or self.
static bool hasScalableVectorType(Type t)
Check if the given type is a scalable vector type or a vector/array type that contains a nested scala...
static OpFoldResult foldChainableCast(T castOp, typename T::FoldAdaptor adaptor)
Folds a cast op that can be chained.
static void destructureIndices(Type currType, ArrayRef< GEPArg > indices, SmallVectorImpl< int32_t > &rawConstantIndices, SmallVectorImpl< Value > &dynamicIndices)
Destructures the 'indices' parameter into 'rawConstantIndices' and 'dynamicIndices',...
static ParseResult parseCommonGlobalAndAlias(OpAsmParser &parser, OperationState &result)
Parse common attributes that might show up in the same order in both GlobalOp and AliasOp.
static SmallVector< Type, 1 > getCallOpResultTypes(LLVMFunctionType calleeType)
Gets the MLIR Op-like result types of a LLVMFunctionType.
static Type getI1SameShape(Type type)
Returns a boolean type that has the same shape as type.
Definition: LLVMDialect.cpp:82
static void printCommonGlobalAndAlias(OpAsmPrinter &p, OpType op)
static ParseResult parseLLVMLinkage(OpAsmParser &p, LinkageAttr &val)
static Attribute getBoolAttribute(Type type, MLIRContext *ctx, bool value)
Returns a scalar or vector boolean attribute of the given type.
static LogicalResult verifyCallOpDebugInfo(CallOp callOp, LLVMFuncOp callee)
Verify that an inlinable callsite of a debug-info-bearing function in a debug-info-bearing function h...
static ParseResult parseShuffleType(AsmParser &parser, Type v1Type, Type &resType, DenseI32ArrayAttr mask)
Build the result type of a shuffle vector operation.
static LogicalResult verifyExtOp(ExtOp op)
Verifies that the given extension operation operates on consistent scalars or vectors,...
static constexpr const char kElemTypeAttrName[]
Definition: LLVMDialect.cpp:49
static ParseResult parseInsertExtractValueElementType(AsmParser &parser, Type &valueType, Type containerType, DenseI64ArrayAttr position)
Infer the value type from the container type and position.
static LogicalResult verifyStructIndices(Type baseGEPType, unsigned indexPos, GEPIndicesAdaptor< ValueRange > indices, function_ref< InFlightDiagnostic()> emitOpError)
For the given indices, check if they comply with baseGEPType, especially check against LLVMStructType...
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
static void printInsertExtractValueElementType(AsmPrinter &printer, Operation *op, Type valueType, Type containerType, DenseI64ArrayAttr position)
Nothing to print for an inferred type.
#define REGISTER_ENUM_TYPE(Ty)
@ None
static std::string diag(const llvm::Value &value)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static VectorType getVectorType(Type scalarTy, const VectorizationStrategy *strategy)
Returns the vector type resulting from applying the provided vectorization strategy on the scalar typ...
This base class exposes generic asm parser hooks, usable across the various derived parsers.
ParseResult parseSymbolName(StringAttr &result)
Parse an -identifier and store it (without the '@' symbol) in a string attribute.
@ Paren
Parens surrounding zero or more operands.
@ None
Zero or more operands with no delimiters.
@ Square
Square brackets surrounding zero or more operands.
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
virtual ParseResult parseColonTypeList(SmallVectorImpl< Type > &result)=0
Parse a colon followed by a type list, which must have at least one type.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:72
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseOptionalColonTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional colon followed by a type list, which if present must have at least one type.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual ParseResult parseCustomAttributeWithFallback(Attribute &result, Type type, function_ref< ParseResult(Attribute &result, Type type)> parseAttribute)=0
Parse a custom attribute with the provided callback, unless the next token is #, in which case the ge...
ParseResult parseString(std::string *string)
Parse a quoted string token.
virtual ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalRSquare()=0
Parse a ] token if present.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
Definition: AsmPrinter.cpp:77
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class provides an abstraction over the different types of ranges over Blocks.
Definition: BlockSupport.h:106
Block represents an ordered list of Operations.
Definition: Block.h:33
bool empty()
Definition: Block.h:148
BlockArgument getArgument(unsigned i)
Definition: Block.h:129
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:244
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:153
Operation & front()
Definition: Block.h:153
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:31
static BoolAttr get(MLIRContext *context, bool value)
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:51
UnitAttr getUnitAttr()
Definition: Builders.cpp:98
IntegerAttr getI32IntegerAttr(int32_t value)
Definition: Builders.cpp:200
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
Definition: Builders.cpp:163
IntegerAttr getI64IntegerAttr(int64_t value)
Definition: Builders.cpp:112
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
Definition: Builders.h:91
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:262
TypedAttr getZeroAttr(Type type)
Definition: Builders.cpp:324
MLIRContext * getContext() const
Definition: Builders.h:56
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:266
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
Definition: Builders.cpp:104
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition: Builders.cpp:94
ArrayAttr getStrArrayAttr(ArrayRef< StringRef > values)
Definition: Builders.cpp:306
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
Definition: Builders.h:98
The main mechanism for performing data layout queries.
static DataLayout closest(Operation *op)
Returns the layout of the closest parent operation carrying layout info.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
An attribute that represents a reference to a dense vector or tensor object.
std::enable_if_t<!std::is_base_of< Attribute, T >::value||std::is_same< Attribute, T >::value, T > getSplatValue() const
Return the splat value for this attribute.
auto getValues() const
Return the held element values as a range of the given type.
Type getElementType() const
Return the element type of this DenseElementsAttr.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
An attribute that represents a reference to a dense integer vector or tensor object.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
A symbol reference with a reference path containing a single element.
StringRef getValue() const
Returns the name of the held symbol reference.
StringAttr getAttr() const
Returns the name of the held symbol reference as a StringAttr.
This class represents a fused location whose metadata is known to be an instance of the given type.
Definition: Location.h:149
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:316
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:354
Class used for building a 'llvm.getelementptr'.
Definition: LLVMDialect.h:71
Class used for convenient access and iteration over GEP indices.
Definition: LLVMDialect.h:118
bool isDynamicIndex(size_t index) const
Returns whether the GEP index at the given position is a dynamic index.
Definition: LLVMDialect.h:147
size_t size() const
Returns the amount of indices of the GEPOp.
Definition: LLVMDialect.h:152
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
This class provides a mutable adaptor for a range of operands.
Definition: ValueRange.h:118
std::optional< NamedAttribute > getNamed(StringRef name) const
Return the specified named attribute if present, std::nullopt otherwise.
Attribute erase(StringAttr name)
Erase the attribute with the given name from the list.
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:164
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:55
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:179
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult parseSuccessor(Block *&dest)=0
Parse a single operation successor.
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
virtual OptionalParseResult parseOptionalOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single operand if present.
virtual ParseResult parseSuccessorAndUseList(Block *&dest, SmallVectorImpl< Value > &operands)=0
Parse a single operation successor and its operand list.
virtual OptionalParseResult parseOptionalRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region if present.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printNewline()=0
Print a newline and indent the printer to the start of the current operation.
virtual void printSuccessorAndUseList(Block *successor, ValueRange succOperands)=0
Print the successor and its operands.
void printOperands(const ContainerType &container)
Print a comma separated list of operands.
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
virtual void printOperand(Value value)=0
Print implementations for various things an operation contains.
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:348
This class helps build Operations.
Definition: Builders.h:207
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition: Builders.cpp:430
Listener * getListener() const
Returns the current listener of this builder, or nullptr if this builder doesn't have a listener.
Definition: Builders.h:320
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
Definition: Builders.h:442
This class represents a single result from folding an operation.
Definition: OpDefinition.h:272
This class provides the API for ops that are known to be isolated from above.
A trait used to provide symbol table functionalities to a region operation.
Definition: SymbolTable.h:452
This class represents a contiguous range of operand ranges, e.g.
Definition: ValueRange.h:84
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:43
type_range getTypes() const
Definition: ValueRange.cpp:28
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:749
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition: Operation.h:238
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:673
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:40
ParseResult value() const
Access the internal ParseResult value.
Definition: OpDefinition.h:53
bool has_value() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:50
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
iterator_range< OpIterator > getOps()
Definition: Region.h:172
bool empty()
Definition: Region.h:60
Block & emplaceBlock()
Definition: Region.h:46
This class represents a specific instance of an effect.
static DerivedEffect * get()
Returns a unique instance for the derived effect class.
This class models how operands are forwarded to block arguments in control flow.
This class implements the successor iterators for Block.
Definition: BlockSupport.h:73
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
virtual Operation * lookupSymbolIn(Operation *symbolTableOp, StringAttr symbol)
Look up a symbol with the specified name within the specified symbol table operation,...
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:76
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
This class provides an abstraction for a range of TypeRange.
Definition: TypeRange.h:95
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:35
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition: Types.cpp:122
bool isSignlessIntOrIndexOrFloat() const
Return true if this is a signless integer, index, or float type.
Definition: Types.cpp:104
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:105
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:18
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: WalkResult.h:29
static WalkResult skip()
Definition: WalkResult.h:48
static WalkResult advance()
Definition: WalkResult.h:47
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: WalkResult.h:51
static WalkResult interrupt()
Definition: WalkResult.h:46
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Builder from ArrayRef<T>.
A named class for passing around the variadic flag.
void addBytecodeInterface(LLVMDialect *dialect)
Add the interfaces necessary for encoding the LLVM dialect components in bytecode.
Value createGlobalString(Location loc, OpBuilder &builder, StringRef name, StringRef value, Linkage linkage)
Create an LLVM global containing the string "value" at the module containing surrounding the insertio...
Operation * parentLLVMModule(Operation *op)
Lookup parent Module satisfying LLVM conditions on the Module Operation.
Type getVectorType(Type elementType, unsigned numElements, bool isScalable=false)
Creates an LLVM dialect-compatible vector type with the given element type and length.
Definition: LLVMTypes.cpp:867
bool isScalableVectorType(Type vectorType)
Returns whether a vector type is scalable or not.
Definition: LLVMTypes.cpp:861
bool isCompatibleVectorType(Type type)
Returns true if the given type is a vector type compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:839
bool isCompatibleOuterType(Type type)
Returns true if the given outer type is compatible with the LLVM dialect without checking its potenti...
Definition: LLVMTypes.cpp:716
bool satisfiesLLVMModule(Operation *op)
LLVM requires some operations to be inside of a Module operation.
constexpr int kGEPConstantBitWidth
Bit-width of a 'GEPConstantIndex' within GEPArg.
Definition: LLVMDialect.h:62
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:809
bool isTypeCompatibleWithAtomicOp(Type type, const DataLayout &dataLayout)
Returns true if the given type is supported by atomic operations.
bool isCompatibleFloatingPointType(Type type)
Returns true if the given type is a floating-point type compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:834
llvm::ElementCount getVectorNumElements(Type type)
Returns the element count of any LLVM-compatible vector type.
Definition: LLVMTypes.cpp:853
void printFunctionSignature(OpAsmPrinter &p, TypeRange argTypes, ArrayAttr argAttrs, bool isVariadic, TypeRange resultTypes, ArrayAttr resultAttrs, Region *body=nullptr, bool printEmptyResult=true)
Print a function signature for a call or callable operation.
ParseResult parseFunctionSignature(OpAsmParser &parser, SmallVectorImpl< Type > &argTypes, SmallVectorImpl< DictionaryAttr > &argAttrs, SmallVectorImpl< Type > &resultTypes, SmallVectorImpl< DictionaryAttr > &resultAttrs, bool mustParseEmptyResult=true)
Parses a function signature using parser.
void addArgAndResultAttrs(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs, StringAttr argAttrsName, StringAttr resAttrsName)
Adds argument and result attributes, provided as argAttrs and resultAttrs arguments,...
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation.
Definition: Visitors.h:102
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
ParseResult parseFunctionSignatureWithArguments(OpAsmParser &parser, bool allowVariadic, SmallVectorImpl< OpAsmParser::Argument > &arguments, bool &isVariadic, SmallVectorImpl< Type > &resultTypes, SmallVectorImpl< DictionaryAttr > &resultAttrs)
Parses a function signature using parser.
void printFunctionAttributes(OpAsmPrinter &p, Operation *op, ArrayRef< StringRef > elided={})
Prints the list of function prefixed with the "attributes" keyword.
void printFunctionSignature(OpAsmPrinter &p, FunctionOpInterface op, ArrayRef< Type > argTypes, bool isVariadic, ArrayRef< Type > resultTypes)
Prints the signature of the function-like operation op.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
Definition: Utils.cpp:18
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:21
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:561
Value constantIndex(OpBuilder &builder, Location loc, int64_t i)
Generates a constant of index type.
Definition: CodegenUtils.h:331
Visibility
This enum describes C++ inheritance visibility.
Definition: Class.h:426
std::string stringify(T &&t)
Generically convert a value to a std::string.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition: Matchers.h:490
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
Definition: Matchers.h:527
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:304
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Definition: Matchers.h:369
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:423
A callable is either a symbol, or an SSA value, that is referenced by a call-like operation.
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
T & getOrAddProperties()
Get (or create) a properties of the provided type to be set on the operation on creation.
SmallVector< Value, 4 > operands
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
void addSuccessors(Block *successor)
Adds a successor to the operation sate. successor must not be null.
void addTypes(ArrayRef< Type > newTypes)
NamedAttrList attributes
Region * addRegion()
Create a region that should be attached to the operation.