MLIR 24.0.0git
LLVMAttrs.cpp
Go to the documentation of this file.
1//===- LLVMAttrs.cpp - LLVM Attributes 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 attribute details for the LLVM IR dialect in MLIR.
10//
11//===----------------------------------------------------------------------===//
12
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/BinaryFormat/Dwarf.h"
20#include "llvm/IR/DebugInfoMetadata.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/Support/ErrorHandling.h"
23
24using namespace mlir;
25using namespace mlir::LLVM;
26
27/// Parses DWARF expression arguments with respect to the DWARF operation
28/// opcode. Some DWARF expression operations have a specific number of operands
29/// and may appear in a textual form.
30static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
32
33/// Prints DWARF expression arguments with respect to the specific DWARF
34/// operation. Some operands are printed in their textual form.
35static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
37
38/// Parses a source language from either the historical inline `DW_LANG_*`
39/// syntax or a nested `DISourceLanguageNameAttr`.
40static ParseResult parseSourceLanguage(AsmParser &parser,
41 DISourceLanguageNameAttr &language);
42
43/// Prints an unversioned source language without a dialect using the
44/// historical inline `DW_LANG_*` syntax. All other source languages are
45/// printed as a nested `DISourceLanguageNameAttr`.
46static void printSourceLanguage(AsmPrinter &printer,
47 DISourceLanguageNameAttr language);
48
49#include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc"
50#include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
51#define GET_ATTRDEF_CLASSES
52#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
53
54//===----------------------------------------------------------------------===//
55// LLVMDialect registration
56//===----------------------------------------------------------------------===//
57
58void LLVMDialect::registerAttributes() {
59 addAttributes<
60#define GET_ATTRDEF_LIST
61#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
62
63 >();
64}
65
66//===----------------------------------------------------------------------===//
67// AddressSpaceAttr
68//===----------------------------------------------------------------------===//
69
70/// Checks whether the given type is an LLVM type that can be loaded or stored.
72 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
73 const ::mlir::DataLayout *dataLayout,
75 if (!isLoadableType(type)) {
76 if (emitError)
77 emitError() << "type must be LLVM type with size, but got " << type;
78 return false;
79 }
80 if (ordering == ptr::AtomicOrdering::not_atomic)
81 return true;
82
83 // To check atomic validity we need a datalayout.
84 if (!dataLayout) {
85 if (emitError)
86 emitError() << "expected a valid data layout";
87 return false;
88 }
89 if (!isTypeCompatibleWithAtomicOp(type, *dataLayout)) {
90 if (emitError)
91 emitError() << "unsupported type " << type << " for atomic access";
92 return false;
93 }
94 return true;
95}
96
97bool AddressSpaceAttr::isValidLoad(
98 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
99 const ::mlir::DataLayout *dataLayout,
101 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,
102 emitError);
103}
104
105bool AddressSpaceAttr::isValidStore(
106 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
107 const ::mlir::DataLayout *dataLayout,
109 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,
110 emitError);
111}
112
113bool AddressSpaceAttr::isValidAtomicOp(
114 ptr::AtomicBinOp op, Type type, ptr::AtomicOrdering ordering,
115 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,
117 // TODO: update this method once `ptr.atomic_rmw` is implemented.
118 assert(false && "unimplemented, see TODO in the source.");
119 return false;
120}
121
122bool AddressSpaceAttr::isValidAtomicXchg(
123 Type type, ptr::AtomicOrdering successOrdering,
124 ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,
125 const ::mlir::DataLayout *dataLayout,
127 // TODO: update this method once `ptr.atomic_cmpxchg` is implemented.
128 assert(false && "unimplemented, see TODO in the source.");
129 return false;
130}
131
132bool AddressSpaceAttr::isValidAddrSpaceCast(
134 // TODO: update this method once the `ptr.addrspace_cast` op is added to the
135 // dialect.
136 assert(false && "unimplemented, see TODO in the source.");
137 return false;
138}
139
140bool AddressSpaceAttr::isValidPtrIntCast(
141 Type intLikeTy, Type ptrLikeTy,
143 // TODO: update this method once the int-cast ops are added to the `ptr`
144 // dialect.
145 assert(false && "unimplemented, see TODO in the source.");
146 return false;
147}
148
149//===----------------------------------------------------------------------===//
150// FunctionMetadataAttr
151//===----------------------------------------------------------------------===//
152
153static constexpr unsigned kReservedFunctionMetadataKinds[] = {
154 llvm::LLVMContext::MD_dbg, llvm::LLVMContext::MD_prof};
155
156static StringRef getFixedMetadataKindName(unsigned kind) {
157 switch (kind) {
158#define LLVM_FIXED_MD_KIND(EnumID, Name, Value) \
159 case llvm::LLVMContext::EnumID: \
160 return Name;
161#include "llvm/IR/FixedMetadataKinds.def"
162#undef LLVM_FIXED_MD_KIND
163 }
164 llvm_unreachable("unknown fixed metadata kind");
165}
166
167LogicalResult
168FunctionMetadataAttr::verify(function_ref<InFlightDiagnostic()> emitError,
169 StringAttr metadataName, MDNodeAttr node) {
170 (void)node;
171 StringRef name = metadataName.getValue();
172 if (name.empty())
173 return emitError() << "function_metadata entry name must not be empty";
174 if (llvm::any_of(kReservedFunctionMetadataKinds, [&](unsigned kind) {
175 return name == getFixedMetadataKindName(kind);
176 })) {
177 return emitError() << "reserved function_metadata entry '" << name
178 << "' is not supported by the generic carrier";
179 }
180 return success();
181}
182
183//===----------------------------------------------------------------------===//
184// AliasScopeAttr
185//===----------------------------------------------------------------------===//
186
187LogicalResult
188AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError,
189 Attribute id, AliasScopeDomainAttr domain,
190 StringAttr description) {
191 (void)domain;
192 (void)description;
193 if (!llvm::isa<StringAttr, DistinctAttr>(id))
194 return emitError()
195 << "id of an alias scope must be a StringAttr or a DistrinctAttr";
196
197 return success();
198}
199
200//===----------------------------------------------------------------------===//
201// DINodeAttr
202//===----------------------------------------------------------------------===//
203
205 return llvm::isa<
206 DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,
207 DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr,
208 DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr,
209 DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,
210 DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,
211 DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
212 attr);
213}
214
215//===----------------------------------------------------------------------===//
216// DIScopeAttr
217//===----------------------------------------------------------------------===//
218
220 return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,
221 DIDerivedTypeAttr, DIFileAttr, DILocalScopeAttr,
222 DIModuleAttr, DINamespaceAttr>(attr);
223}
224
225//===----------------------------------------------------------------------===//
226// DILocalScopeAttr
227//===----------------------------------------------------------------------===//
228
230 return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,
231 DISubprogramAttr>(attr);
232}
233
234//===----------------------------------------------------------------------===//
235// DIVariableAttr
236//===----------------------------------------------------------------------===//
237
239 return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);
240}
241
242//===----------------------------------------------------------------------===//
243// DITypeAttr
244//===----------------------------------------------------------------------===//
245
247 return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,
248 DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(
249 attr);
250}
251
252//===----------------------------------------------------------------------===//
253// DIDerivedTypeAttr
254//===----------------------------------------------------------------------===//
255
256LogicalResult DIDerivedTypeAttr::verify(
257 function_ref<InFlightDiagnostic()> emitError, unsigned tag, StringAttr name,
258 DIFileAttr file, uint32_t line, DIScopeAttr scope, DITypeAttr baseType,
259 uint64_t sizeInBits, uint32_t alignInBits, uint64_t offsetInBits,
260 std::optional<unsigned> dwarfAddressSpace, DIFlags flags,
261 Attribute extraData) {
262 if (extraData && !llvm::isa<DINodeAttr, IntegerAttr>(extraData))
263 return emitError() << "extraData must be a DINodeAttr or an IntegerAttr";
264 return success();
265}
266
267//===----------------------------------------------------------------------===//
268// TBAANodeAttr
269//===----------------------------------------------------------------------===//
270
272 return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
273}
274
275//===----------------------------------------------------------------------===//
276// MemProfMIBAttr
277//===----------------------------------------------------------------------===//
278
279LogicalResult
280MemProfMIBAttr::verify(function_ref<InFlightDiagnostic()> emitError,
281 DenseI64ArrayAttr callStack, StringAttr,
283 // The call stack feeds `Verifier::visitCallStackMetadata`, which needs at
284 // least one frame hash. The other parameters are typed, so an empty stack
285 // is the only bad shape that can get here.
286 if (callStack.empty())
287 return emitError() << "call stack of a memprof MemInfoBlock must not be "
288 "empty";
289 return success();
290}
291
292//===----------------------------------------------------------------------===//
293// MemoryEffectsAttr
294//===----------------------------------------------------------------------===//
295
296MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context,
297 ArrayRef<ModRefInfo> memInfoArgs) {
298 if (memInfoArgs.empty())
299 return MemoryEffectsAttr::get(context, /*other=*/ModRefInfo::ModRef,
300 /*argMem=*/ModRefInfo::ModRef,
301 /*inaccessibleMem=*/ModRefInfo::ModRef,
302 /*errnoMem=*/ModRefInfo::ModRef,
303 /*targetMem0=*/ModRefInfo::ModRef,
304 /*targetMem1=*/ModRefInfo::ModRef);
305 if (memInfoArgs.size() == 6)
306 return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1],
307 memInfoArgs[2], memInfoArgs[3],
308 memInfoArgs[4], memInfoArgs[5]);
309 return {};
310}
311
312bool MemoryEffectsAttr::isReadWrite() {
313 if (this->getArgMem() != ModRefInfo::ModRef)
314 return false;
315 if (this->getInaccessibleMem() != ModRefInfo::ModRef)
316 return false;
317 if (this->getOther() != ModRefInfo::ModRef)
318 return false;
319 if (this->getErrnoMem() != ModRefInfo::ModRef)
320 return false;
321 if (this->getTargetMem0() != ModRefInfo::ModRef)
322 return false;
323 if (this->getTargetMem1() != ModRefInfo::ModRef)
324 return false;
325 return true;
326}
327
328//===----------------------------------------------------------------------===//
329// DIExpression
330//===----------------------------------------------------------------------===//
331
332DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {
333 return get(context, ArrayRef<DIExpressionElemAttr>({}));
334}
335
336ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
337 SmallVector<uint64_t> &args) {
338 auto operandParser = [&]() -> LogicalResult {
339 uint64_t operand = 0;
340 if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
341 // Attempt to parse a keyword.
342 StringRef keyword;
343 if (succeeded(parser.parseOptionalKeyword(&keyword))) {
344 operand = llvm::dwarf::getAttributeEncoding(keyword);
345 if (operand == 0) {
346 // The keyword is invalid.
347 return parser.emitError(parser.getCurrentLocation())
348 << "encountered unknown attribute encoding \"" << keyword
349 << "\"";
350 }
351 }
352 }
353
354 // operand should be non-zero if a keyword was parsed. Otherwise, the
355 // operand MUST be an integer.
356 if (operand == 0) {
357 // Parse the next operand as an integer.
358 if (parser.parseInteger(operand)) {
359 return parser.emitError(parser.getCurrentLocation())
360 << "expected integer operand";
361 }
362 }
363
364 args.push_back(operand);
365 return success();
366 };
367
368 // Parse operands as a comma-separated list.
369 return parser.parseCommaSeparatedList(operandParser);
370}
371
372void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
373 ArrayRef<uint64_t> args) {
374 size_t i = 0;
375 llvm::interleaveComma(args, printer, [&](uint64_t operand) {
376 if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {
377 if (const StringRef keyword =
378 llvm::dwarf::AttributeEncodingString(operand);
379 !keyword.empty()) {
380 printer << keyword;
381 return;
382 }
383 }
384 // All operands are expected to be printed as integers.
385 printer << operand;
386 i++;
387 });
388}
389
390//===----------------------------------------------------------------------===//
391// DICompositeTypeAttr
392//===----------------------------------------------------------------------===//
393
394DIRecursiveTypeAttrInterface
395DICompositeTypeAttr::withRecId(DistinctAttr recId) {
396 return DICompositeTypeAttr::get(
397 getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),
398 getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
399 getAlignInBits(), getDataLocation(), getRank(), getAllocated(),
400 getAssociated(), getIdentifier(), getDiscriminator(), getElements());
401}
402
403DIRecursiveTypeAttrInterface
404DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
405 return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
406 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
407 {}, {}, {}, {}, {});
408}
409
410//===----------------------------------------------------------------------===//
411// DISourceLanguageNameAttr
412//===----------------------------------------------------------------------===//
413
414static ParseResult parseSourceLanguage(AsmParser &parser,
415 DISourceLanguageNameAttr &language) {
416 DISourceLanguageNameAttr nestedLanguage;
417 OptionalParseResult nestedResult =
418 parser.parseOptionalAttribute(nestedLanguage);
419 if (nestedResult.has_value()) {
420 if (failed(*nestedResult))
421 return failure();
422 language = nestedLanguage;
423 return success();
424 }
425
426 // If we cannot parse the full attr, try to just parse a DWARF language.
427 SMLoc loc = parser.getCurrentLocation();
428 StringRef spelling;
429 if (parser.parseKeyword(&spelling))
430 return failure();
431 if (unsigned value = llvm::dwarf::getLanguage(spelling)) {
432 language = DISourceLanguageNameAttr::get(
433 parser.getContext(), value, /*name=*/0, /*version=*/std::nullopt,
434 /*dialect=*/0);
435 return success();
436 }
437 return parser.emitError(loc)
438 << "invalid debug info source language: " << spelling;
439}
440
441static void printSourceLanguage(AsmPrinter &printer,
442 DISourceLanguageNameAttr language) {
443 // Print only the DWARF language if the other fields are not set.
444 if (language.getLanguage() && !language.getName() && !language.getVersion() &&
445 !language.getDialect()) {
446 printer << llvm::dwarf::LanguageString(language.getLanguage());
447 return;
448 }
449 printer.printAttribute(language);
450}
451
452LogicalResult DISourceLanguageNameAttr::verify(
453 function_ref<InFlightDiagnostic()> emitError, unsigned language,
454 unsigned name, std::optional<uint32_t> version, unsigned /*dialect*/) {
455 if (static_cast<bool>(language) == static_cast<bool>(name))
456 return emitError() << "expected exactly one of language or name";
457 if (name && !version)
458 return emitError() << "DW_LNAME requires a version";
459 if (language && version)
460 return emitError() << "DW_LANG cannot have a version";
461 return success();
462}
463
464//===----------------------------------------------------------------------===//
465// DICompileUnitAttr
466//===----------------------------------------------------------------------===//
467
468DIRecursiveTypeAttrInterface DICompileUnitAttr::withRecId(DistinctAttr recId) {
469 return DICompileUnitAttr::get(
470 getContext(), recId, getIsRecSelf(), getId(), getSourceLanguage(),
471 getFile(), getProducer(), getIsOptimized(), getEmissionKind(),
472 getIsDebugInfoForProfiling(), getNameTableKind(), getSplitDebugFilename(),
473 getImportedEntities());
474}
475
476DIRecursiveTypeAttrInterface DICompileUnitAttr::getRecSelf(DistinctAttr recId) {
477
478 return DICompileUnitAttr::get(
479 recId.getContext(), recId, /*isRecSelf=*/true, /*id=*/{},
480 /*sourceLanguage=*/{},
481 /*file=*/{}, /*producer=*/{}, /*isOptimized=*/false, DIEmissionKind::None,
482 /*isDebugInfoForProfiling=*/false, DINameTableKind::Default,
483 /*splitDebugFilename=*/{}, /*importedEntities=*/{});
484}
485
486LogicalResult DICompileUnitAttr::verify(
487 function_ref<InFlightDiagnostic()> emitError, DistinctAttr recId,
488 bool isRecSelf, DistinctAttr id, DISourceLanguageNameAttr sourceLanguage,
489 DIFileAttr file, StringAttr producer, bool isOptimized,
490 DIEmissionKind emissionKind, bool isDebugInfoForProfiling,
491 DINameTableKind nameTableKind, StringAttr splitDebugFilename,
492 ArrayRef<DINodeAttr> importedEntities) {
493 if (isRecSelf)
494 return success();
495 if (!sourceLanguage)
496 return emitError() << "sourceLanguage must be set";
497 return success();
498}
499
500//===----------------------------------------------------------------------===//
501// DISubprogramAttr
502//===----------------------------------------------------------------------===//
503
504DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
505 return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),
506 getCompileUnit(), getScope(), getName(),
507 getLinkageName(), getFile(), getLine(),
508 getScopeLine(), getSubprogramFlags(), getType(),
509 getRetainedNodes(), getAnnotations());
510}
511
512DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
513 return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
514 {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
515}
516
517//===----------------------------------------------------------------------===//
518// ConstantRangeAttr
519//===----------------------------------------------------------------------===//
520
521Attribute ConstantRangeAttr::parse(AsmParser &parser, Type odsType) {
522 llvm::SMLoc loc = parser.getCurrentLocation();
523 IntegerType widthType;
524 if (parser.parseLess() || parser.parseType(widthType) ||
525 parser.parseComma()) {
526 return Attribute{};
527 }
528 unsigned bitWidth = widthType.getWidth();
529 APInt lower(bitWidth, 0);
530 APInt upper(bitWidth, 0);
531 if (parser.parseInteger(lower) || parser.parseComma() ||
532 parser.parseInteger(upper) || parser.parseGreater())
533 return Attribute{};
534 // Non-positive numbers may use more bits than `bitWidth`
535 lower = lower.sextOrTrunc(bitWidth);
536 upper = upper.sextOrTrunc(bitWidth);
537 return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower,
538 upper);
539}
540
541void ConstantRangeAttr::print(AsmPrinter &printer) const {
542 printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "
543 << getUpper() << ">";
544}
545
546LogicalResult
547ConstantRangeAttr::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
548 APInt lower, APInt upper) {
549 if (lower.getBitWidth() != upper.getBitWidth())
550 return emitError()
551 << "expected lower and upper to have matching bitwidths but got "
552 << lower.getBitWidth() << " vs. " << upper.getBitWidth();
553 return success();
554}
555
556//===----------------------------------------------------------------------===//
557// TargetFeaturesAttr
558//===----------------------------------------------------------------------===//
559
560TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
561 llvm::ArrayRef<StringRef> features) {
562 return Base::get(context,
563 llvm::map_to_vector(features, [&](StringRef feature) {
564 return StringAttr::get(context, feature);
565 }));
566}
567
568TargetFeaturesAttr
569TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
570 MLIRContext *context,
571 llvm::ArrayRef<StringRef> features) {
572 return Base::getChecked(emitError, context,
573 llvm::map_to_vector(features, [&](StringRef feature) {
574 return StringAttr::get(context, feature);
575 }));
576}
577
578TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,
579 StringRef targetFeatures) {
580 SmallVector<StringRef> features;
581 targetFeatures.split(features, ',', /*MaxSplit=*/-1,
582 /*KeepEmpty=*/false);
583 return get(context, features);
584}
585
586TargetFeaturesAttr
587TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
588 MLIRContext *context, StringRef targetFeatures) {
589 SmallVector<StringRef> features;
590 targetFeatures.split(features, ',', /*MaxSplit=*/-1,
591 /*KeepEmpty=*/false);
592 ArrayRef featuresRef(features);
593 return getChecked(emitError, context, featuresRef);
594}
595
596LogicalResult
597TargetFeaturesAttr::verify(function_ref<InFlightDiagnostic()> emitError,
598 llvm::ArrayRef<StringAttr> features) {
599 for (StringAttr featureAttr : features) {
600 if (!featureAttr || featureAttr.empty())
601 return emitError() << "target features can not be null or empty";
602 auto feature = featureAttr.strref();
603 if (feature[0] != '+' && feature[0] != '-')
604 return emitError() << "target features must start with '+' or '-'";
605 if (feature.contains(','))
606 return emitError() << "target features can not contain ','";
607 }
608 return success();
609}
610
611bool TargetFeaturesAttr::contains(StringAttr feature) const {
612 if (nullOrEmpty())
613 return false;
614 // Note: Using StringAttr does pointer comparisons.
615 return llvm::is_contained(getFeatures(), feature);
616}
617
618bool TargetFeaturesAttr::contains(StringRef feature) const {
619 if (nullOrEmpty())
620 return false;
621 return llvm::is_contained(getFeatures(), feature);
622}
623
624std::string TargetFeaturesAttr::getFeaturesString() const {
625 std::string featuresString;
626 llvm::raw_string_ostream ss(featuresString);
627 llvm::interleave(
628 getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ",");
629 return featuresString;
630}
631
632TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) {
633 auto parentFunction = op->getParentOfType<FunctionOpInterface>();
634 if (!parentFunction)
635 return {};
636 Operation *parentOp = parentFunction.getOperation();
637 if (auto llvmFunc = dyn_cast<LLVMFuncOp>(parentOp))
638 return llvmFunc.getTargetFeaturesAttr();
639
640 // Dynamic operation definitions do not support direct inherent attribute
641 // lookup. Use the safe walker for other FunctionOpInterface implementations.
642 TargetFeaturesAttr targetFeatures;
643 parentOp->getName().walkInherentAttrs(
644 parentOp, [&](StringRef name, Attribute &attr) {
645 if (name == getAttributeName())
646 targetFeatures = dyn_cast<TargetFeaturesAttr>(attr);
647 });
648 if (targetFeatures)
649 return targetFeatures;
650 return parentOp->getDiscardableAttrOfType<TargetFeaturesAttr>(
651 getAttributeName());
652}
653
654FailureOr<Attribute> TargetFeaturesAttr::query(DataLayoutEntryKey key) {
655 auto stringKey = dyn_cast<StringAttr>(key);
656 if (!stringKey)
657 return failure();
658
659 if (contains(stringKey))
660 return UnitAttr::get(getContext());
661
662 if (contains((std::string("+") + stringKey.strref()).str()))
663 return BoolAttr::get(getContext(), true);
664
665 if (contains((std::string("-") + stringKey.strref()).str()))
666 return BoolAttr::get(getContext(), false);
667
668 return failure();
669}
670
671//===----------------------------------------------------------------------===//
672// TargetAttr
673//===----------------------------------------------------------------------===//
674
675FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) {
676 if (auto stringAttrKey = dyn_cast<StringAttr>(key)) {
677 if (stringAttrKey.getValue() == "triple")
678 return getTriple();
679 if (stringAttrKey.getValue() == "chip")
680 return getChip();
681 if (stringAttrKey.getValue() == "features" && getFeatures())
682 return getFeatures();
683 }
684 return failure();
685}
686
687//===----------------------------------------------------------------------===//
688// ModuleFlagAttr
689//===----------------------------------------------------------------------===//
690
692 StringAttr key, Attribute value,
694 if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
695 auto arrayAttr = dyn_cast<ArrayAttr>(value);
696 if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {
697 return isa<ModuleFlagCGProfileEntryAttr>(attr);
698 })))
699 return emitError()
700 << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";
701 return success();
702 }
703
704 if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {
705 if (!isa<ModuleFlagProfileSummaryAttr>(value))
706 return emitError() << "'ProfileSummary' key expects a "
707 "'#llvm.profile_summary' attribute";
708 return success();
709 }
710
711 if (isa<IntegerAttr, StringAttr, IntrinsicIntegerAttrInterface>(value))
712 return success();
713
714 // Allow non-empty ArrayAttr of StringAttrs to represent MDTuples of
715 // MDStrings (e.g. the "riscv-isa" module flag). Integer values within
716 // MDTuples are not handled here because integer module flags are encoded as
717 // ConstantAsMetadata at the top level (not as MDTuples), so no known use
718 // case requires an array-of-integers representation.
719 if (auto arrayAttr = dyn_cast<ArrayAttr>(value))
720 if (!arrayAttr.empty() &&
721 llvm::all_of(arrayAttr, [](Attribute a) { return isa<StringAttr>(a); }))
722 return success();
723
724 return emitError()
725 << "only integer, integer-like dialect attributes, string, "
726 "and string-array values are currently supported for "
727 "unknown key '"
728 << key << "'";
729}
730
731LogicalResult
732ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
733 LLVM::ModFlagBehavior flagBehavior, StringAttr key,
734 Attribute value) {
736}
737
738ModFlagBehavior ModuleFlagAttr::getModuleFlagBehavior() const {
739 return getBehavior();
740}
741
742StringAttr ModuleFlagAttr::getModuleFlagKey() const { return getKey(); }
743
744Attribute ModuleFlagAttr::getModuleFlagValue() const { return getValue(); }
745
746//===----------------------------------------------------------------------===//
747// MDAddrSpaceCastAttr
748//===----------------------------------------------------------------------===//
749
750LogicalResult
751MDAddrSpaceCastAttr::verify(function_ref<InFlightDiagnostic()> emitError,
752 Attribute arg, unsigned addressSpace) {
753 // `addrspacecast` operates on pointers, so the operand must be a metadata
754 // attribute that models a pointer-typed constant.
755 if (!isa<MDGlobalValueAttr, MDNullAttr, MDAddrSpaceCastAttr>(arg))
756 return emitError() << "expected #llvm.md_global_value, #llvm.md_null, or "
757 "#llvm.md_addrspacecast operand, but got "
758 << arg;
759 return success();
760}
return success()
static llvm::DISourceLanguageName getSourceLanguage(DICompileUnitAttr attr)
static StringRef getFixedMetadataKindName(unsigned kind)
static void printExpressionArg(AsmPrinter &printer, uint64_t opcode, ArrayRef< uint64_t > args)
Prints DWARF expression arguments with respect to the specific DWARF operation.
static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, SmallVector< uint64_t > &args)
Parses DWARF expression arguments with respect to the DWARF operation opcode.
static ParseResult parseSourceLanguage(AsmParser &parser, DISourceLanguageNameAttr &language)
Parses a source language from either the historical inline DW_LANG_* syntax or a nested DISourceLangu...
static constexpr unsigned kReservedFunctionMetadataKinds[]
static void printSourceLanguage(AsmPrinter &printer, DISourceLanguageNameAttr language)
Prints an unversioned source language without a dialect using the historical inline DW_LANG_* syntax.
b getContext())
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
static arith::FastMathFlags getFlags(arith::FastMathFlagsAttr fastmath)
Returns the flags held by fastmath, or none if it is null.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
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 parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual OptionalParseResult parseOptionalAttribute(Attribute &result, Type type={})=0
Parse an arbitrary optional attribute of a given type and return it in result.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
auto getChecked(SMLoc loc, ParamsT &&...params)
Invoke the getChecked method of the given Attribute or Type class, using the provided location to emi...
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printAttribute(Attribute attr)
Attributes are known-constant values of operations.
Definition Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
static BoolAttr get(MLIRContext *context, bool value)
This class represents a diagnostic that is inflight and set to be reported.
This class represents a LLVM attribute that describes a local debug info scope.
Definition LLVMAttrs.h:48
static bool classof(Attribute attr)
Support LLVM type casting.
constexpr Attribute()=default
static bool classof(Attribute attr)
This class represents a LLVM attribute that describes a debug info scope.
Definition LLVMAttrs.h:38
static bool classof(Attribute attr)
Support LLVM type casting.
This class represents a LLVM attribute that describes a debug info type.
Definition LLVMAttrs.h:57
static bool classof(Attribute attr)
Support LLVM type casting.
static bool classof(Attribute attr)
Support LLVM type casting.
static bool classof(Attribute attr)
Support LLVM type casting.
constexpr Attribute()=default
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
void walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) const
Visit the inherent attributes stored in the properties of op.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
Definition Operation.h:495
This class implements Optional functionality for ParseResult.
bool has_value() const
Returns true if we contain a valid ParseResult value.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
LogicalResult verifyModuleFlagValue(StringAttr key, Attribute value, function_ref< InFlightDiagnostic()> emitError)
Verifies that a module flag value can be exported to LLVM IR.
bool isValidLoadStoreImpl(Type type, ptr::AtomicOrdering ordering, std::optional< int64_t > alignment, const ::mlir::DataLayout *dataLayout, function_ref< InFlightDiagnostic()> emitError)
Checks whether the given type is an LLVM type that can be loaded or stored.
Definition LLVMAttrs.cpp:71
bool isLoadableType(Type type)
Returns true if the given type is a loadable type compatible with the LLVM dialect.
bool isTypeCompatibleWithAtomicOp(Type type, const DataLayout &dataLayout)
Returns true if the given type is supported by atomic operations.
Include the generated interface declarations.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
llvm::PointerUnion< Type, StringAttr > DataLayoutEntryKey
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:311
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto getChecked(function_ref< InFlightDiagnostic()> emitError, MLIRContext *context, Ts &&...params)
Helper method analogous to get, but uses getChecked when available to allow graceful failure on inval...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::function_ref< Fn > function_ref
Definition LLVM.h:155