//===- LLVMAttrs.cpp - LLVM Attributes registration -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the attribute details for the LLVM IR dialect in MLIR. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" #include "mlir/Interfaces/FunctionInterfaces.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/DebugInfoMetadata.h" #include using namespace mlir; using namespace mlir::LLVM; /// Parses DWARF expression arguments with respect to the DWARF operation /// opcode. Some DWARF expression operations have a specific number of operands /// and may appear in a textual form. static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, SmallVector &args); /// Prints DWARF expression arguments with respect to the specific DWARF /// operation. Some operands are printed in their textual form. static void printExpressionArg(AsmPrinter &printer, uint64_t opcode, ArrayRef args); #include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc" #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" //===----------------------------------------------------------------------===// // LLVMDialect registration //===----------------------------------------------------------------------===// void LLVMDialect::registerAttributes() { addAttributes< #define GET_ATTRDEF_LIST #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" >(); } //===----------------------------------------------------------------------===// // AliasScopeAttr //===----------------------------------------------------------------------===// LogicalResult AliasScopeAttr::verify(function_ref emitError, Attribute id, AliasScopeDomainAttr domain, StringAttr description) { (void)domain; (void)description; if (!llvm::isa(id)) return emitError() << "id of an alias scope must be a StringAttr or a DistrinctAttr"; return success(); } //===----------------------------------------------------------------------===// // DINodeAttr //===----------------------------------------------------------------------===// bool DINodeAttr::classof(Attribute attr) { return llvm::isa< DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr, DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr, DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>( attr); } //===----------------------------------------------------------------------===// // DIScopeAttr //===----------------------------------------------------------------------===// bool DIScopeAttr::classof(Attribute attr) { return llvm::isa( attr); } //===----------------------------------------------------------------------===// // DILocalScopeAttr //===----------------------------------------------------------------------===// bool DILocalScopeAttr::classof(Attribute attr) { return llvm::isa(attr); } //===----------------------------------------------------------------------===// // DIVariableAttr //===----------------------------------------------------------------------===// bool DIVariableAttr::classof(Attribute attr) { return llvm::isa(attr); } //===----------------------------------------------------------------------===// // DITypeAttr //===----------------------------------------------------------------------===// bool DITypeAttr::classof(Attribute attr) { return llvm::isa( attr); } //===----------------------------------------------------------------------===// // TBAANodeAttr //===----------------------------------------------------------------------===// bool TBAANodeAttr::classof(Attribute attr) { return llvm::isa(attr); } //===----------------------------------------------------------------------===// // MemoryEffectsAttr //===----------------------------------------------------------------------===// MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context, ArrayRef memInfoArgs) { if (memInfoArgs.empty()) return MemoryEffectsAttr::get(context, ModRefInfo::ModRef, ModRefInfo::ModRef, ModRefInfo::ModRef); if (memInfoArgs.size() == 3) return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1], memInfoArgs[2]); return {}; } bool MemoryEffectsAttr::isReadWrite() { if (this->getArgMem() != ModRefInfo::ModRef) return false; if (this->getInaccessibleMem() != ModRefInfo::ModRef) return false; if (this->getOther() != ModRefInfo::ModRef) return false; return true; } //===----------------------------------------------------------------------===// // DIExpression //===----------------------------------------------------------------------===// DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) { return get(context, ArrayRef({})); } ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, SmallVector &args) { auto operandParser = [&]() -> LogicalResult { uint64_t operand = 0; if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) { // Attempt to parse a keyword. StringRef keyword; if (succeeded(parser.parseOptionalKeyword(&keyword))) { operand = llvm::dwarf::getAttributeEncoding(keyword); if (operand == 0) { // The keyword is invalid. return parser.emitError(parser.getCurrentLocation()) << "encountered unknown attribute encoding \"" << keyword << "\""; } } } // operand should be non-zero if a keyword was parsed. Otherwise, the // operand MUST be an integer. if (operand == 0) { // Parse the next operand as an integer. if (parser.parseInteger(operand)) { return parser.emitError(parser.getCurrentLocation()) << "expected integer operand"; } } args.push_back(operand); return success(); }; // Parse operands as a comma-separated list. return parser.parseCommaSeparatedList(operandParser); } void printExpressionArg(AsmPrinter &printer, uint64_t opcode, ArrayRef args) { size_t i = 0; llvm::interleaveComma(args, printer, [&](uint64_t operand) { if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) { if (const StringRef keyword = llvm::dwarf::AttributeEncodingString(operand); !keyword.empty()) { printer << keyword; return; } } // All operands are expected to be printed as integers. printer << operand; i++; }); } //===----------------------------------------------------------------------===// // DICompositeTypeAttr //===----------------------------------------------------------------------===// DIRecursiveTypeAttrInterface DICompositeTypeAttr::withRecId(DistinctAttr recId) { return DICompositeTypeAttr::get( getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(), getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(), getAlignInBits(), getElements(), getDataLocation(), getRank(), getAllocated(), getAssociated()); } DIRecursiveTypeAttrInterface DICompositeTypeAttr::getRecSelf(DistinctAttr recId) { return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {}, {}, {}, {}); } //===----------------------------------------------------------------------===// // DISubprogramAttr //===----------------------------------------------------------------------===// DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) { return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(), getCompileUnit(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getScopeLine(), getSubprogramFlags(), getType(), getRetainedNodes(), getAnnotations()); } DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) { return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}); } //===----------------------------------------------------------------------===// // ConstantRangeAttr //===----------------------------------------------------------------------===// Attribute ConstantRangeAttr::parse(AsmParser &parser, Type odsType) { llvm::SMLoc loc = parser.getCurrentLocation(); IntegerType widthType; if (parser.parseLess() || parser.parseType(widthType) || parser.parseComma()) { return Attribute{}; } unsigned bitWidth = widthType.getWidth(); APInt lower(bitWidth, 0); APInt upper(bitWidth, 0); if (parser.parseInteger(lower) || parser.parseComma() || parser.parseInteger(upper) || parser.parseGreater()) return Attribute{}; // Non-positive numbers may use more bits than `bitWidth` lower = lower.sextOrTrunc(bitWidth); upper = upper.sextOrTrunc(bitWidth); return parser.getChecked(loc, parser.getContext(), lower, upper); } void ConstantRangeAttr::print(AsmPrinter &printer) const { printer << ""; } LogicalResult ConstantRangeAttr::verify(llvm::function_ref emitError, APInt lower, APInt upper) { if (lower.getBitWidth() != upper.getBitWidth()) return emitError() << "expected lower and upper to have matching bitwidths but got " << lower.getBitWidth() << " vs. " << upper.getBitWidth(); return success(); } //===----------------------------------------------------------------------===// // TargetFeaturesAttr //===----------------------------------------------------------------------===// TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, llvm::ArrayRef features) { return Base::get(context, llvm::map_to_vector(features, [&](StringRef feature) { return StringAttr::get(context, feature); })); } TargetFeaturesAttr TargetFeaturesAttr::getChecked(function_ref emitError, MLIRContext *context, llvm::ArrayRef features) { return Base::getChecked(emitError, context, llvm::map_to_vector(features, [&](StringRef feature) { return StringAttr::get(context, feature); })); } TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, StringRef targetFeatures) { SmallVector features; targetFeatures.split(features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); return get(context, features); } TargetFeaturesAttr TargetFeaturesAttr::getChecked(function_ref emitError, MLIRContext *context, StringRef targetFeatures) { SmallVector features; targetFeatures.split(features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); ArrayRef featuresRef(features); return getChecked(emitError, context, featuresRef); } LogicalResult TargetFeaturesAttr::verify(function_ref emitError, llvm::ArrayRef features) { for (StringAttr featureAttr : features) { if (!featureAttr || featureAttr.empty()) return emitError() << "target features can not be null or empty"; auto feature = featureAttr.strref(); if (feature[0] != '+' && feature[0] != '-') return emitError() << "target features must start with '+' or '-'"; if (feature.contains(',')) return emitError() << "target features can not contain ','"; } return success(); } bool TargetFeaturesAttr::contains(StringAttr feature) const { if (nullOrEmpty()) return false; // Note: Using StringAttr does pointer comparisons. return llvm::is_contained(getFeatures(), feature); } bool TargetFeaturesAttr::contains(StringRef feature) const { if (nullOrEmpty()) return false; return llvm::is_contained(getFeatures(), feature); } std::string TargetFeaturesAttr::getFeaturesString() const { std::string featuresString; llvm::raw_string_ostream ss(featuresString); llvm::interleave( getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ","); return featuresString; } TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) { auto parentFunction = op->getParentOfType(); if (!parentFunction) return {}; return parentFunction.getOperation()->getAttrOfType( getAttributeName()); }