brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.8 KiB · db39c70 Raw
518 lines · cpp
1//===- DebugImporter.cpp - LLVM to MLIR Debug conversion ------------------===//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#include "DebugImporter.h"10#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"11#include "mlir/IR/Attributes.h"12#include "mlir/IR/BuiltinAttributes.h"13#include "mlir/IR/Location.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/TypeSwitch.h"16#include "llvm/BinaryFormat/Dwarf.h"17#include "llvm/IR/Constants.h"18#include "llvm/IR/DebugInfoMetadata.h"19#include "llvm/IR/Metadata.h"20 21using namespace mlir;22using namespace mlir::LLVM;23using namespace mlir::LLVM::detail;24 25DebugImporter::DebugImporter(ModuleOp mlirModule,26                             bool dropDICompositeTypeElements)27    : cache([&](llvm::DINode *node) { return createRecSelf(node); }),28      context(mlirModule.getContext()), mlirModule(mlirModule),29      dropDICompositeTypeElements(dropDICompositeTypeElements) {}30 31Location DebugImporter::translateFuncLocation(llvm::Function *func) {32  llvm::DISubprogram *subprogram = func->getSubprogram();33  if (!subprogram)34    return UnknownLoc::get(context);35 36  // Add a fused location to link the subprogram information.37  StringAttr fileName = StringAttr::get(context, subprogram->getFilename());38  return FusedLocWith<DISubprogramAttr>::get(39      {FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0)},40      translate(subprogram), context);41}42 43//===----------------------------------------------------------------------===//44// Attributes45//===----------------------------------------------------------------------===//46 47DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) {48  return DIBasicTypeAttr::get(context, node->getTag(), node->getName(),49                              node->getSizeInBits(), node->getEncoding());50}51 52DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {53  std::optional<DIEmissionKind> emissionKind =54      symbolizeDIEmissionKind(node->getEmissionKind());55  std::optional<DINameTableKind> nameTableKind = symbolizeDINameTableKind(56      static_cast<57          std::underlying_type_t<llvm::DICompileUnit::DebugNameTableKind>>(58          node->getNameTableKind()));59  return DICompileUnitAttr::get(60      context, getOrCreateDistinctID(node),61      node->getSourceLanguage().getUnversionedName(),62      translate(node->getFile()), getStringAttrOrNull(node->getRawProducer()),63      node->isOptimized(), emissionKind.value(), nameTableKind.value(),64      getStringAttrOrNull(node->getRawSplitDebugFilename()));65}66 67DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {68  std::optional<DIFlags> flags = symbolizeDIFlags(node->getFlags());69  SmallVector<DINodeAttr> elements;70 71  // A vector always requires an element.72  bool isVectorType = flags && bitEnumContainsAll(*flags, DIFlags::Vector);73  if (isVectorType || !dropDICompositeTypeElements) {74    for (llvm::DINode *element : node->getElements()) {75      assert(element && "expected a non-null element type");76      elements.push_back(translate(element));77    }78  }79  // Drop the elements parameter if any of the elements are invalid.80  if (llvm::is_contained(elements, nullptr))81    elements.clear();82  DITypeAttr baseType = translate(node->getBaseType());83  // Arrays require a base type, otherwise the debug metadata is considered to84  // be malformed.85  if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType)86    return nullptr;87  return DICompositeTypeAttr::get(88      context, node->getTag(), getStringAttrOrNull(node->getRawName()),89      translate(node->getFile()), node->getLine(), translate(node->getScope()),90      baseType, flags.value_or(DIFlags::Zero), node->getSizeInBits(),91      node->getAlignInBits(), translateExpression(node->getDataLocationExp()),92      translateExpression(node->getRankExp()),93      translateExpression(node->getAllocatedExp()),94      translateExpression(node->getAssociatedExp()), elements);95}96 97DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) {98  // Return nullptr if the base type is invalid.99  DITypeAttr baseType = translate(node->getBaseType());100  if (node->getBaseType() && !baseType)101    return nullptr;102  DINodeAttr extraData =103      translate(dyn_cast_or_null<llvm::DINode>(node->getExtraData()));104  return DIDerivedTypeAttr::get(105      context, node->getTag(), getStringAttrOrNull(node->getRawName()),106      baseType, node->getSizeInBits(), node->getAlignInBits(),107      node->getOffsetInBits(), node->getDWARFAddressSpace(), extraData);108}109 110DIStringTypeAttr DebugImporter::translateImpl(llvm::DIStringType *node) {111  return DIStringTypeAttr::get(112      context, node->getTag(), getStringAttrOrNull(node->getRawName()),113      node->getSizeInBits(), node->getAlignInBits(),114      translate(node->getStringLength()),115      translateExpression(node->getStringLengthExp()),116      translateExpression(node->getStringLocationExp()), node->getEncoding());117}118 119DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {120  return DIFileAttr::get(context, node->getFilename(), node->getDirectory());121}122 123DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) {124  // Return nullptr if the scope or type is a cyclic dependency.125  DIScopeAttr scope = translate(node->getScope());126  if (node->getScope() && !scope)127    return nullptr;128  return DILabelAttr::get(context, scope,129                          getStringAttrOrNull(node->getRawName()),130                          translate(node->getFile()), node->getLine());131}132 133DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) {134  // Return nullptr if the scope or type is a cyclic dependency.135  DIScopeAttr scope = translate(node->getScope());136  if (node->getScope() && !scope)137    return nullptr;138  return DILexicalBlockAttr::get(context, scope, translate(node->getFile()),139                                 node->getLine(), node->getColumn());140}141 142DILexicalBlockFileAttr143DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) {144  // Return nullptr if the scope or type is a cyclic dependency.145  DIScopeAttr scope = translate(node->getScope());146  if (node->getScope() && !scope)147    return nullptr;148  return DILexicalBlockFileAttr::get(context, scope, translate(node->getFile()),149                                     node->getDiscriminator());150}151 152DIGlobalVariableAttr153DebugImporter::translateImpl(llvm::DIGlobalVariable *node) {154  // Names of DIGlobalVariables can be empty. MLIR models them as null, instead155  // of empty strings, so this special handling is necessary.156  auto convertToStringAttr = [&](StringRef name) -> StringAttr {157    if (name.empty())158      return {};159    return StringAttr::get(context, node->getName());160  };161  return DIGlobalVariableAttr::get(162      context, translate(node->getScope()),163      convertToStringAttr(node->getName()),164      convertToStringAttr(node->getLinkageName()), translate(node->getFile()),165      node->getLine(), translate(node->getType()), node->isLocalToUnit(),166      node->isDefinition(), node->getAlignInBits());167}168 169DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) {170  // Return nullptr if the scope or type is a cyclic dependency.171  DIScopeAttr scope = translate(node->getScope());172  if (node->getScope() && !scope)173    return nullptr;174  return DILocalVariableAttr::get(175      context, scope, getStringAttrOrNull(node->getRawName()),176      translate(node->getFile()), node->getLine(), node->getArg(),177      node->getAlignInBits(), translate(node->getType()),178      symbolizeDIFlags(node->getFlags()).value_or(DIFlags::Zero));179}180 181DIVariableAttr DebugImporter::translateImpl(llvm::DIVariable *node) {182  return cast<DIVariableAttr>(translate(static_cast<llvm::DINode *>(node)));183}184 185DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) {186  return cast<DIScopeAttr>(translate(static_cast<llvm::DINode *>(node)));187}188 189DIModuleAttr DebugImporter::translateImpl(llvm::DIModule *node) {190  return DIModuleAttr::get(191      context, translate(node->getFile()), translate(node->getScope()),192      getStringAttrOrNull(node->getRawName()),193      getStringAttrOrNull(node->getRawConfigurationMacros()),194      getStringAttrOrNull(node->getRawIncludePath()),195      getStringAttrOrNull(node->getRawAPINotesFile()), node->getLineNo(),196      node->getIsDecl());197}198 199DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {200  return DINamespaceAttr::get(context, getStringAttrOrNull(node->getRawName()),201                              translate(node->getScope()),202                              node->getExportSymbols());203}204 205DIImportedEntityAttr206DebugImporter::translateImpl(llvm::DIImportedEntity *node) {207  SmallVector<DINodeAttr> elements;208  for (llvm::DINode *element : node->getElements()) {209    assert(element && "expected a non-null element type");210    elements.push_back(translate(element));211  }212 213  return DIImportedEntityAttr::get(214      context, node->getTag(), translate(node->getScope()),215      translate(node->getEntity()), translate(node->getFile()), node->getLine(),216      getStringAttrOrNull(node->getRawName()), elements);217}218 219DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {220  // Only definitions require a distinct identifier.221  mlir::DistinctAttr id;222  if (node->isDistinct())223    id = getOrCreateDistinctID(node);224 225  // Return nullptr if the scope or type is invalid.226  DIScopeAttr scope = translate(node->getScope());227  if (node->getScope() && !scope)228    return nullptr;229  std::optional<DISubprogramFlags> subprogramFlags =230      symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags());231  assert(subprogramFlags && "expected valid subprogram flags");232  DISubroutineTypeAttr type = translate(node->getType());233  if (node->getType() && !type)234    return nullptr;235 236  // Convert the retained nodes but drop all of them if one of them is invalid.237  SmallVector<DINodeAttr> retainedNodes;238  for (llvm::DINode *retainedNode : node->getRetainedNodes())239    retainedNodes.push_back(translate(retainedNode));240  if (llvm::is_contained(retainedNodes, nullptr))241    retainedNodes.clear();242 243  SmallVector<DINodeAttr> annotations;244  // We currently only support `string` values for annotations on the MLIR side.245  // Theoretically we could support other primitives, but LLVM is not using246  // other types in practice.247  if (llvm::DINodeArray rawAnns = node->getAnnotations(); rawAnns) {248    for (size_t i = 0, e = rawAnns->getNumOperands(); i < e; ++i) {249      const llvm::MDTuple *tuple = cast<llvm::MDTuple>(rawAnns->getOperand(i));250      if (tuple->getNumOperands() != 2)251        continue;252      const llvm::MDString *name = cast<llvm::MDString>(tuple->getOperand(0));253      const llvm::MDString *value =254          dyn_cast<llvm::MDString>(tuple->getOperand(1));255      if (name && value) {256        annotations.push_back(DIAnnotationAttr::get(257            context, StringAttr::get(context, name->getString()),258            StringAttr::get(context, value->getString())));259      }260    }261  }262 263  return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,264                               getStringAttrOrNull(node->getRawName()),265                               getStringAttrOrNull(node->getRawLinkageName()),266                               translate(node->getFile()), node->getLine(),267                               node->getScopeLine(), *subprogramFlags, type,268                               retainedNodes, annotations);269}270 271DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {272  auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute {273    if (data.isNull())274      return nullptr;275    if (auto *constInt = dyn_cast<llvm::ConstantInt *>(data))276      return IntegerAttr::get(IntegerType::get(context, 64),277                              constInt->getSExtValue());278    if (auto *expr = dyn_cast<llvm::DIExpression *>(data))279      return translateExpression(expr);280    if (auto *var = dyn_cast<llvm::DIVariable *>(data)) {281      if (auto *local = dyn_cast<llvm::DILocalVariable>(var))282        return translate(local);283      if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var))284        return translate(global);285      return nullptr;286    }287    return nullptr;288  };289  Attribute count = getAttrOrNull(node->getCount());290  Attribute upperBound = getAttrOrNull(node->getUpperBound());291  // Either count or the upper bound needs to be present. Otherwise, the292  // metadata is invalid. The conversion might fail due to unsupported DI nodes.293  if (!count && !upperBound)294    return {};295  return DISubrangeAttr::get(context, count,296                             getAttrOrNull(node->getLowerBound()), upperBound,297                             getAttrOrNull(node->getStride()));298}299 300DICommonBlockAttr DebugImporter::translateImpl(llvm::DICommonBlock *node) {301  return DICommonBlockAttr::get(context, translate(node->getScope()),302                                translate(node->getDecl()),303                                getStringAttrOrNull(node->getRawName()),304                                translate(node->getFile()), node->getLineNo());305}306 307DIGenericSubrangeAttr308DebugImporter::translateImpl(llvm::DIGenericSubrange *node) {309  auto getAttrOrNull =310      [&](llvm::DIGenericSubrange::BoundType data) -> Attribute {311    if (data.isNull())312      return nullptr;313    if (auto *expr = dyn_cast<llvm::DIExpression *>(data))314      return translateExpression(expr);315    if (auto *var = dyn_cast<llvm::DIVariable *>(data)) {316      if (auto *local = dyn_cast<llvm::DILocalVariable>(var))317        return translate(local);318      if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var))319        return translate(global);320      return nullptr;321    }322    return nullptr;323  };324  Attribute count = getAttrOrNull(node->getCount());325  Attribute upperBound = getAttrOrNull(node->getUpperBound());326  Attribute lowerBound = getAttrOrNull(node->getLowerBound());327  Attribute stride = getAttrOrNull(node->getStride());328  // Either count or the upper bound needs to be present. Otherwise, the329  // metadata is invalid.330  if (!count && !upperBound)331    return {};332  return DIGenericSubrangeAttr::get(context, count, lowerBound, upperBound,333                                    stride);334}335 336DISubroutineTypeAttr337DebugImporter::translateImpl(llvm::DISubroutineType *node) {338  SmallVector<DITypeAttr> types;339  for (llvm::DIType *type : node->getTypeArray()) {340    if (!type) {341      // A nullptr entry may appear at the beginning or the end of the342      // subroutine types list modeling either a void result type or the type of343      // a variadic argument. Translate the nullptr to an explicit344      // DINullTypeAttr since the attribute list cannot contain a nullptr entry.345      types.push_back(DINullTypeAttr::get(context));346      continue;347    }348    types.push_back(translate(type));349  }350  // Return nullptr if any of the types is invalid.351  if (llvm::is_contained(types, nullptr))352    return nullptr;353  return DISubroutineTypeAttr::get(context, node->getCC(), types);354}355 356DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {357  return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));358}359 360DINodeAttr DebugImporter::translate(llvm::DINode *node) {361  if (!node)362    return nullptr;363 364  // Check for a cached instance.365  auto cacheEntry = cache.lookupOrInit(node);366  if (std::optional<DINodeAttr> result = cacheEntry.get())367    return *result;368 369  // Convert the debug metadata if possible.370  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {371    if (auto *casted = dyn_cast<llvm::DIBasicType>(node))372      return translateImpl(casted);373    if (auto *casted = dyn_cast<llvm::DICommonBlock>(node))374      return translateImpl(casted);375    if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))376      return translateImpl(casted);377    if (auto *casted = dyn_cast<llvm::DICompositeType>(node))378      return translateImpl(casted);379    if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))380      return translateImpl(casted);381    if (auto *casted = dyn_cast<llvm::DIStringType>(node))382      return translateImpl(casted);383    if (auto *casted = dyn_cast<llvm::DIFile>(node))384      return translateImpl(casted);385    if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))386      return translateImpl(casted);387    if (auto *casted = dyn_cast<llvm::DIImportedEntity>(node))388      return translateImpl(casted);389    if (auto *casted = dyn_cast<llvm::DILabel>(node))390      return translateImpl(casted);391    if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))392      return translateImpl(casted);393    if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))394      return translateImpl(casted);395    if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))396      return translateImpl(casted);397    if (auto *casted = dyn_cast<llvm::DIModule>(node))398      return translateImpl(casted);399    if (auto *casted = dyn_cast<llvm::DINamespace>(node))400      return translateImpl(casted);401    if (auto *casted = dyn_cast<llvm::DISubprogram>(node))402      return translateImpl(casted);403    if (auto *casted = dyn_cast<llvm::DISubrange>(node))404      return translateImpl(casted);405    if (auto *casted = dyn_cast<llvm::DIGenericSubrange>(node))406      return translateImpl(casted);407    if (auto *casted = dyn_cast<llvm::DISubroutineType>(node))408      return translateImpl(casted);409    return nullptr;410  };411  if (DINodeAttr attr = translateNode(node)) {412    // If this node was repeated, lookup its recursive ID and assign it to the413    // base result.414    if (cacheEntry.wasRepeated()) {415      DistinctAttr recId = nodeToRecId.lookup(node);416      auto recType = cast<DIRecursiveTypeAttrInterface>(attr);417      attr = cast<DINodeAttr>(recType.withRecId(recId));418    }419    cacheEntry.resolve(attr);420    return attr;421  }422  cacheEntry.resolve(nullptr);423  return nullptr;424}425 426/// Get the `getRecSelf` constructor for the translated type of `node` if its427/// translated DITypeAttr supports recursion. Otherwise, returns nullptr.428static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>429getRecSelfConstructor(llvm::DINode *node) {430  using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>;431  return TypeSwitch<llvm::DINode *, CtorType>(node)432      .Case([&](llvm::DICompositeType *) {433        return CtorType(DICompositeTypeAttr::getRecSelf);434      })435      .Case([&](llvm::DISubprogram *) {436        return CtorType(DISubprogramAttr::getRecSelf);437      })438      .Default(CtorType());439}440 441std::optional<DINodeAttr> DebugImporter::createRecSelf(llvm::DINode *node) {442  auto recSelfCtor = getRecSelfConstructor(node);443  if (!recSelfCtor)444    return std::nullopt;445 446  // The original node may have already been assigned a recursive ID from447  // a different self-reference. Use that if possible.448  DistinctAttr recId = nodeToRecId.lookup(node);449  if (!recId) {450    recId = DistinctAttr::create(UnitAttr::get(context));451    nodeToRecId[node] = recId;452  }453  DIRecursiveTypeAttrInterface recSelf = recSelfCtor(recId);454  return cast<DINodeAttr>(recSelf);455}456 457//===----------------------------------------------------------------------===//458// Locations459//===----------------------------------------------------------------------===//460 461Location DebugImporter::translateLoc(llvm::DILocation *loc) {462  if (!loc)463    return UnknownLoc::get(context);464 465  // Get the file location of the instruction.466  Location result = FileLineColLoc::get(context, loc->getFilename(),467                                        loc->getLine(), loc->getColumn());468 469  // Add scope information.470  assert(loc->getScope() && "expected non-null scope");471  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),472                                          context);473 474  // Add call site information, if available.475  if (llvm::DILocation *inlinedAt = loc->getInlinedAt())476    result = CallSiteLoc::get(result, translateLoc(inlinedAt));477 478  return result;479}480 481DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) {482  if (!node)483    return nullptr;484 485  SmallVector<DIExpressionElemAttr> ops;486 487  // Begin processing the operations.488  for (const llvm::DIExpression::ExprOperand &op : node->expr_ops()) {489    SmallVector<uint64_t> operands;490    operands.reserve(op.getNumArgs());491    for (const auto &i : llvm::seq(op.getNumArgs()))492      operands.push_back(op.getArg(i));493    const auto attr = DIExpressionElemAttr::get(context, op.getOp(), operands);494    ops.push_back(attr);495  }496  return DIExpressionAttr::get(context, ops);497}498 499DIGlobalVariableExpressionAttr DebugImporter::translateGlobalVariableExpression(500    llvm::DIGlobalVariableExpression *node) {501  return DIGlobalVariableExpressionAttr::get(502      context, translate(node->getVariable()),503      translateExpression(node->getExpression()));504}505 506StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {507  if (!stringNode)508    return StringAttr();509  return StringAttr::get(context, stringNode->getString());510}511 512DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {513  DistinctAttr &id = nodeToDistinctAttr[node];514  if (!id)515    id = DistinctAttr::create(UnitAttr::get(context));516  return id;517}518