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