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