brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.1 KiB · 9f87e50 Raw
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