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