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