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