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