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