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