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