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