538 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the attribute details for the LLVM IR dialect in MLIR.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"14#include "mlir/Dialect/LLVMIR/LLVMDialect.h"15#include "mlir/Dialect/LLVMIR/LLVMTypes.h"16#include "mlir/Dialect/Ptr/IR/PtrEnums.h"17#include "mlir/IR/Builders.h"18#include "mlir/IR/DialectImplementation.h"19#include "mlir/Interfaces/FunctionInterfaces.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/ADT/TypeSwitch.h"22#include "llvm/BinaryFormat/Dwarf.h"23 24using namespace mlir;25using namespace mlir::LLVM;26 27/// Parses DWARF expression arguments with respect to the DWARF operation28/// opcode. Some DWARF expression operations have a specific number of operands29/// and may appear in a textual form.30static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,31 SmallVector<uint64_t> &args);32 33/// Prints DWARF expression arguments with respect to the specific DWARF34/// operation. Some operands are printed in their textual form.35static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,36 ArrayRef<uint64_t> args);37 38#include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc"39#include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"40#define GET_ATTRDEF_CLASSES41#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"42 43//===----------------------------------------------------------------------===//44// LLVMDialect registration45//===----------------------------------------------------------------------===//46 47void LLVMDialect::registerAttributes() {48 addAttributes<49#define GET_ATTRDEF_LIST50#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"51 52 >();53}54 55//===----------------------------------------------------------------------===//56// AddressSpaceAttr57//===----------------------------------------------------------------------===//58 59/// Checks whether the given type is an LLVM type that can be loaded or stored.60bool LLVM::detail::isValidLoadStoreImpl(61 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,62 const ::mlir::DataLayout *dataLayout,63 function_ref<InFlightDiagnostic()> emitError) {64 if (!isLoadableType(type)) {65 if (emitError)66 emitError() << "type must be LLVM type with size, but got " << type;67 return false;68 }69 if (ordering == ptr::AtomicOrdering::not_atomic)70 return true;71 72 // To check atomic validity we need a datalayout.73 if (!dataLayout) {74 if (emitError)75 emitError() << "expected a valid data layout";76 return false;77 }78 if (!isTypeCompatibleWithAtomicOp(type, *dataLayout)) {79 if (emitError)80 emitError() << "unsupported type " << type << " for atomic access";81 return false;82 }83 return true;84}85 86bool AddressSpaceAttr::isValidLoad(87 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,88 const ::mlir::DataLayout *dataLayout,89 function_ref<InFlightDiagnostic()> emitError) const {90 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,91 emitError);92}93 94bool AddressSpaceAttr::isValidStore(95 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,96 const ::mlir::DataLayout *dataLayout,97 function_ref<InFlightDiagnostic()> emitError) const {98 return detail::isValidLoadStoreImpl(type, ordering, alignment, dataLayout,99 emitError);100}101 102bool AddressSpaceAttr::isValidAtomicOp(103 ptr::AtomicBinOp op, Type type, ptr::AtomicOrdering ordering,104 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,105 function_ref<InFlightDiagnostic()> emitError) const {106 // TODO: update this method once `ptr.atomic_rmw` is implemented.107 assert(false && "unimplemented, see TODO in the source.");108 return false;109}110 111bool AddressSpaceAttr::isValidAtomicXchg(112 Type type, ptr::AtomicOrdering successOrdering,113 ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,114 const ::mlir::DataLayout *dataLayout,115 function_ref<InFlightDiagnostic()> emitError) const {116 // TODO: update this method once `ptr.atomic_cmpxchg` is implemented.117 assert(false && "unimplemented, see TODO in the source.");118 return false;119}120 121bool AddressSpaceAttr::isValidAddrSpaceCast(122 Type tgt, Type src, function_ref<InFlightDiagnostic()> emitError) const {123 // TODO: update this method once the `ptr.addrspace_cast` op is added to the124 // dialect.125 assert(false && "unimplemented, see TODO in the source.");126 return false;127}128 129bool AddressSpaceAttr::isValidPtrIntCast(130 Type intLikeTy, Type ptrLikeTy,131 function_ref<InFlightDiagnostic()> emitError) const {132 // TODO: update this method once the int-cast ops are added to the `ptr`133 // dialect.134 assert(false && "unimplemented, see TODO in the source.");135 return false;136}137 138//===----------------------------------------------------------------------===//139// AliasScopeAttr140//===----------------------------------------------------------------------===//141 142LogicalResult143AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError,144 Attribute id, AliasScopeDomainAttr domain,145 StringAttr description) {146 (void)domain;147 (void)description;148 if (!llvm::isa<StringAttr, DistinctAttr>(id))149 return emitError()150 << "id of an alias scope must be a StringAttr or a DistrinctAttr";151 152 return success();153}154 155//===----------------------------------------------------------------------===//156// DINodeAttr157//===----------------------------------------------------------------------===//158 159bool DINodeAttr::classof(Attribute attr) {160 return llvm::isa<161 DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,162 DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr,163 DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr,164 DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,165 DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,166 DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(167 attr);168}169 170//===----------------------------------------------------------------------===//171// DIScopeAttr172//===----------------------------------------------------------------------===//173 174bool DIScopeAttr::classof(Attribute attr) {175 return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr,176 DIDerivedTypeAttr, DIFileAttr, DILocalScopeAttr,177 DIModuleAttr, DINamespaceAttr>(attr);178}179 180//===----------------------------------------------------------------------===//181// DILocalScopeAttr182//===----------------------------------------------------------------------===//183 184bool DILocalScopeAttr::classof(Attribute attr) {185 return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr,186 DISubprogramAttr>(attr);187}188 189//===----------------------------------------------------------------------===//190// DIVariableAttr191//===----------------------------------------------------------------------===//192 193bool DIVariableAttr::classof(Attribute attr) {194 return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr);195}196 197//===----------------------------------------------------------------------===//198// DITypeAttr199//===----------------------------------------------------------------------===//200 201bool DITypeAttr::classof(Attribute attr) {202 return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr,203 DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>(204 attr);205}206 207//===----------------------------------------------------------------------===//208// TBAANodeAttr209//===----------------------------------------------------------------------===//210 211bool TBAANodeAttr::classof(Attribute attr) {212 return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);213}214 215//===----------------------------------------------------------------------===//216// MemoryEffectsAttr217//===----------------------------------------------------------------------===//218 219MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context,220 ArrayRef<ModRefInfo> memInfoArgs) {221 if (memInfoArgs.empty())222 return MemoryEffectsAttr::get(context, /*other=*/ModRefInfo::ModRef,223 /*argMem=*/ModRefInfo::ModRef,224 /*inaccessibleMem=*/ModRefInfo::ModRef,225 /*errnoMem=*/ModRefInfo::ModRef,226 /*targetMem0=*/ModRefInfo::ModRef,227 /*targetMem1=*/ModRefInfo::ModRef);228 if (memInfoArgs.size() == 6)229 return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1],230 memInfoArgs[2], memInfoArgs[3],231 memInfoArgs[4], memInfoArgs[5]);232 return {};233}234 235bool MemoryEffectsAttr::isReadWrite() {236 if (this->getArgMem() != ModRefInfo::ModRef)237 return false;238 if (this->getInaccessibleMem() != ModRefInfo::ModRef)239 return false;240 if (this->getOther() != ModRefInfo::ModRef)241 return false;242 if (this->getErrnoMem() != ModRefInfo::ModRef)243 return false;244 if (this->getTargetMem0() != ModRefInfo::ModRef)245 return false;246 if (this->getTargetMem1() != ModRefInfo::ModRef)247 return false;248 return true;249}250 251//===----------------------------------------------------------------------===//252// DIExpression253//===----------------------------------------------------------------------===//254 255DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) {256 return get(context, ArrayRef<DIExpressionElemAttr>({}));257}258 259ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode,260 SmallVector<uint64_t> &args) {261 auto operandParser = [&]() -> LogicalResult {262 uint64_t operand = 0;263 if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) {264 // Attempt to parse a keyword.265 StringRef keyword;266 if (succeeded(parser.parseOptionalKeyword(&keyword))) {267 operand = llvm::dwarf::getAttributeEncoding(keyword);268 if (operand == 0) {269 // The keyword is invalid.270 return parser.emitError(parser.getCurrentLocation())271 << "encountered unknown attribute encoding \"" << keyword272 << "\"";273 }274 }275 }276 277 // operand should be non-zero if a keyword was parsed. Otherwise, the278 // operand MUST be an integer.279 if (operand == 0) {280 // Parse the next operand as an integer.281 if (parser.parseInteger(operand)) {282 return parser.emitError(parser.getCurrentLocation())283 << "expected integer operand";284 }285 }286 287 args.push_back(operand);288 return success();289 };290 291 // Parse operands as a comma-separated list.292 return parser.parseCommaSeparatedList(operandParser);293}294 295void printExpressionArg(AsmPrinter &printer, uint64_t opcode,296 ArrayRef<uint64_t> args) {297 size_t i = 0;298 llvm::interleaveComma(args, printer, [&](uint64_t operand) {299 if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) {300 if (const StringRef keyword =301 llvm::dwarf::AttributeEncodingString(operand);302 !keyword.empty()) {303 printer << keyword;304 return;305 }306 }307 // All operands are expected to be printed as integers.308 printer << operand;309 i++;310 });311}312 313//===----------------------------------------------------------------------===//314// DICompositeTypeAttr315//===----------------------------------------------------------------------===//316 317DIRecursiveTypeAttrInterface318DICompositeTypeAttr::withRecId(DistinctAttr recId) {319 return DICompositeTypeAttr::get(320 getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),321 getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),322 getAlignInBits(), getDataLocation(), getRank(), getAllocated(),323 getAssociated(), getElements());324}325 326DIRecursiveTypeAttrInterface327DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {328 return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,329 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},330 {}, {}, {});331}332 333//===----------------------------------------------------------------------===//334// DISubprogramAttr335//===----------------------------------------------------------------------===//336 337DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {338 return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),339 getCompileUnit(), getScope(), getName(),340 getLinkageName(), getFile(), getLine(),341 getScopeLine(), getSubprogramFlags(), getType(),342 getRetainedNodes(), getAnnotations());343}344 345DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {346 return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,347 {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});348}349 350//===----------------------------------------------------------------------===//351// ConstantRangeAttr352//===----------------------------------------------------------------------===//353 354Attribute ConstantRangeAttr::parse(AsmParser &parser, Type odsType) {355 llvm::SMLoc loc = parser.getCurrentLocation();356 IntegerType widthType;357 if (parser.parseLess() || parser.parseType(widthType) ||358 parser.parseComma()) {359 return Attribute{};360 }361 unsigned bitWidth = widthType.getWidth();362 APInt lower(bitWidth, 0);363 APInt upper(bitWidth, 0);364 if (parser.parseInteger(lower) || parser.parseComma() ||365 parser.parseInteger(upper) || parser.parseGreater())366 return Attribute{};367 // Non-positive numbers may use more bits than `bitWidth`368 lower = lower.sextOrTrunc(bitWidth);369 upper = upper.sextOrTrunc(bitWidth);370 return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower,371 upper);372}373 374void ConstantRangeAttr::print(AsmPrinter &printer) const {375 printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", "376 << getUpper() << ">";377}378 379LogicalResult380ConstantRangeAttr::verify(llvm::function_ref<InFlightDiagnostic()> emitError,381 APInt lower, APInt upper) {382 if (lower.getBitWidth() != upper.getBitWidth())383 return emitError()384 << "expected lower and upper to have matching bitwidths but got "385 << lower.getBitWidth() << " vs. " << upper.getBitWidth();386 return success();387}388 389//===----------------------------------------------------------------------===//390// TargetFeaturesAttr391//===----------------------------------------------------------------------===//392 393TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,394 llvm::ArrayRef<StringRef> features) {395 return Base::get(context,396 llvm::map_to_vector(features, [&](StringRef feature) {397 return StringAttr::get(context, feature);398 }));399}400 401TargetFeaturesAttr402TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,403 MLIRContext *context,404 llvm::ArrayRef<StringRef> features) {405 return Base::getChecked(emitError, context,406 llvm::map_to_vector(features, [&](StringRef feature) {407 return StringAttr::get(context, feature);408 }));409}410 411TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context,412 StringRef targetFeatures) {413 SmallVector<StringRef> features;414 targetFeatures.split(features, ',', /*MaxSplit=*/-1,415 /*KeepEmpty=*/false);416 return get(context, features);417}418 419TargetFeaturesAttr420TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,421 MLIRContext *context, StringRef targetFeatures) {422 SmallVector<StringRef> features;423 targetFeatures.split(features, ',', /*MaxSplit=*/-1,424 /*KeepEmpty=*/false);425 ArrayRef featuresRef(features);426 return getChecked(emitError, context, featuresRef);427}428 429LogicalResult430TargetFeaturesAttr::verify(function_ref<InFlightDiagnostic()> emitError,431 llvm::ArrayRef<StringAttr> features) {432 for (StringAttr featureAttr : features) {433 if (!featureAttr || featureAttr.empty())434 return emitError() << "target features can not be null or empty";435 auto feature = featureAttr.strref();436 if (feature[0] != '+' && feature[0] != '-')437 return emitError() << "target features must start with '+' or '-'";438 if (feature.contains(','))439 return emitError() << "target features can not contain ','";440 }441 return success();442}443 444bool TargetFeaturesAttr::contains(StringAttr feature) const {445 if (nullOrEmpty())446 return false;447 // Note: Using StringAttr does pointer comparisons.448 return llvm::is_contained(getFeatures(), feature);449}450 451bool TargetFeaturesAttr::contains(StringRef feature) const {452 if (nullOrEmpty())453 return false;454 return llvm::is_contained(getFeatures(), feature);455}456 457std::string TargetFeaturesAttr::getFeaturesString() const {458 std::string featuresString;459 llvm::raw_string_ostream ss(featuresString);460 llvm::interleave(461 getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ",");462 return featuresString;463}464 465TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) {466 auto parentFunction = op->getParentOfType<FunctionOpInterface>();467 if (!parentFunction)468 return {};469 return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>(470 getAttributeName());471}472 473FailureOr<Attribute> TargetFeaturesAttr::query(DataLayoutEntryKey key) {474 auto stringKey = dyn_cast<StringAttr>(key);475 if (!stringKey)476 return failure();477 478 if (contains(stringKey))479 return UnitAttr::get(getContext());480 481 if (contains((std::string("+") + stringKey.strref()).str()))482 return BoolAttr::get(getContext(), true);483 484 if (contains((std::string("-") + stringKey.strref()).str()))485 return BoolAttr::get(getContext(), false);486 487 return failure();488}489 490//===----------------------------------------------------------------------===//491// TargetAttr492//===----------------------------------------------------------------------===//493 494FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) {495 if (auto stringAttrKey = dyn_cast<StringAttr>(key)) {496 if (stringAttrKey.getValue() == "triple")497 return getTriple();498 if (stringAttrKey.getValue() == "chip")499 return getChip();500 if (stringAttrKey.getValue() == "features" && getFeatures())501 return getFeatures();502 }503 return failure();504}505 506//===----------------------------------------------------------------------===//507// ModuleFlagAttr508//===----------------------------------------------------------------------===//509 510LogicalResult511ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,512 LLVM::ModFlagBehavior flagBehavior, StringAttr key,513 Attribute value) {514 if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {515 auto arrayAttr = dyn_cast<ArrayAttr>(value);516 if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {517 return isa<ModuleFlagCGProfileEntryAttr>(attr);518 })))519 return emitError()520 << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";521 return success();522 }523 524 if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {525 if (!isa<ModuleFlagProfileSummaryAttr>(value))526 return emitError() << "'ProfileSummary' key expects a "527 "'#llvm.profile_summary' attribute";528 return success();529 }530 531 if (isa<IntegerAttr, StringAttr>(value))532 return success();533 534 return emitError() << "only integer and string values are currently "535 "supported for unknown key '"536 << key << "'";537}538