615 lines · cpp
1//===- DebugTranslation.cpp - MLIR to LLVM 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 "DebugTranslation.h"10#include "mlir/Dialect/LLVMIR/LLVMDialect.h"11#include "llvm/ADT/TypeSwitch.h"12#include "llvm/IR/Metadata.h"13#include "llvm/IR/Module.h"14#include "llvm/Support/FileSystem.h"15#include "llvm/Support/Path.h"16 17using namespace mlir;18using namespace mlir::LLVM;19using namespace mlir::LLVM::detail;20 21/// A utility walker that interrupts if the operation has valid debug22/// information.23static WalkResult interruptIfValidLocation(Operation *op) {24 return isa<UnknownLoc>(op->getLoc()) ? WalkResult::advance()25 : WalkResult::interrupt();26}27 28DebugTranslation::DebugTranslation(Operation *module, llvm::Module &llvmModule)29 : debugEmissionIsEnabled(false), llvmModule(llvmModule),30 llvmCtx(llvmModule.getContext()) {31 // If the module has no location information, there is nothing to do.32 if (!module->walk(interruptIfValidLocation).wasInterrupted())33 return;34 debugEmissionIsEnabled = true;35}36 37static constexpr StringRef kDebugVersionKey = "Debug Info Version";38static constexpr StringRef kCodeViewKey = "CodeView";39 40void DebugTranslation::addModuleFlagsIfNotPresent() {41 // TODO: The version information should be encoded on the LLVM module itself,42 // not implicitly set here.43 44 // Mark this module as having debug information.45 if (!llvmModule.getModuleFlag(kDebugVersionKey))46 llvmModule.addModuleFlag(llvm::Module::Warning, kDebugVersionKey,47 llvm::DEBUG_METADATA_VERSION);48 49 const llvm::Triple &targetTriple = llvmModule.getTargetTriple();50 if (targetTriple.isKnownWindowsMSVCEnvironment()) {51 // Dwarf debugging files will be generated by default, unless "CodeView"52 // is set explicitly. Windows/MSVC should use CodeView instead.53 if (!llvmModule.getModuleFlag(kCodeViewKey))54 llvmModule.addModuleFlag(llvm::Module::Warning, kCodeViewKey, 1);55 }56}57 58/// Translate the debug information for the given function.59void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {60 if (!debugEmissionIsEnabled)61 return;62 63 // Look for a sub program attached to the function.64 auto spLoc =65 func.getLoc()->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>();66 if (!spLoc)67 return;68 llvmFunc.setSubprogram(translate(spLoc.getMetadata()));69}70 71//===----------------------------------------------------------------------===//72// Attributes73//===----------------------------------------------------------------------===//74 75llvm::DIType *DebugTranslation::translateImpl(DINullTypeAttr attr) {76 // A DINullTypeAttr at the beginning of the subroutine types list models77 // a void result type. If it is at the end, it models a variadic function.78 // Translate the explicit DINullTypeAttr to a nullptr since LLVM IR metadata79 // does not have an explicit void result type nor a variadic type80 // representation.81 return nullptr;82}83 84llvm::DIExpression *85DebugTranslation::getExpressionAttrOrNull(DIExpressionAttr attr) {86 if (!attr)87 return nullptr;88 return translateExpression(attr);89}90 91llvm::MDString *DebugTranslation::getMDStringOrNull(StringAttr stringAttr) {92 if (!stringAttr || stringAttr.empty())93 return nullptr;94 return llvm::MDString::get(llvmCtx, stringAttr);95}96 97llvm::MDTuple *98DebugTranslation::getMDTupleOrNull(ArrayRef<DINodeAttr> elements) {99 if (elements.empty())100 return nullptr;101 SmallVector<llvm::Metadata *> llvmElements = llvm::to_vector(102 llvm::map_range(elements, [&](DINodeAttr attr) -> llvm::Metadata * {103 if (DIAnnotationAttr annAttr = dyn_cast<DIAnnotationAttr>(attr)) {104 llvm::Metadata *ops[2] = {105 llvm::MDString::get(llvmCtx, annAttr.getName()),106 llvm::MDString::get(llvmCtx, annAttr.getValue())};107 return llvm::MDNode::get(llvmCtx, ops);108 }109 return translate(attr);110 }));111 return llvm::MDNode::get(llvmCtx, llvmElements);112}113 114llvm::DIBasicType *DebugTranslation::translateImpl(DIBasicTypeAttr attr) {115 return llvm::DIBasicType::get(116 llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),117 attr.getSizeInBits(),118 /*AlignInBits=*/0, attr.getEncoding(), llvm::DINode::FlagZero);119}120 121llvm::DICompileUnit *DebugTranslation::translateImpl(DICompileUnitAttr attr) {122 llvm::DIBuilder builder(llvmModule);123 return builder.createCompileUnit(124 attr.getSourceLanguage(), translate(attr.getFile()),125 attr.getProducer() ? attr.getProducer().getValue() : "",126 attr.getIsOptimized(),127 /*Flags=*/"", /*RV=*/0,128 attr.getSplitDebugFilename() ? attr.getSplitDebugFilename().getValue()129 : "",130 static_cast<llvm::DICompileUnit::DebugEmissionKind>(131 attr.getEmissionKind()),132 0, true, false,133 static_cast<llvm::DICompileUnit::DebugNameTableKind>(134 attr.getNameTableKind()));135}136 137/// Returns a new `DINodeT` that is either distinct or not, depending on138/// `isDistinct`.139template <class DINodeT, class... Ts>140static DINodeT *getDistinctOrUnique(bool isDistinct, Ts &&...args) {141 if (isDistinct)142 return DINodeT::getDistinct(std::forward<Ts>(args)...);143 return DINodeT::get(std::forward<Ts>(args)...);144}145 146llvm::TempDICompositeType147DebugTranslation::translateTemporaryImpl(DICompositeTypeAttr attr) {148 return llvm::DICompositeType::getTemporary(149 llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()), nullptr,150 attr.getLine(), nullptr, nullptr, attr.getSizeInBits(),151 attr.getAlignInBits(),152 /*OffsetInBits=*/0,153 /*Flags=*/static_cast<llvm::DINode::DIFlags>(attr.getFlags()),154 /*Elements=*/nullptr, /*RuntimeLang=*/0, /*EnumKind=*/std::nullopt,155 /*VTableHolder=*/nullptr);156}157 158llvm::TempDISubprogram159DebugTranslation::translateTemporaryImpl(DISubprogramAttr attr) {160 return llvm::DISubprogram::getTemporary(161 llvmCtx, /*Scope=*/nullptr, /*Name=*/{}, /*LinkageName=*/{},162 /*File=*/nullptr, attr.getLine(), /*Type=*/nullptr,163 /*ScopeLine=*/0, /*ContainingType=*/nullptr, /*VirtualIndex=*/0,164 /*ThisAdjustment=*/0, llvm::DINode::FlagZero,165 static_cast<llvm::DISubprogram::DISPFlags>(attr.getSubprogramFlags()),166 /*Unit=*/nullptr);167}168 169llvm::DICompositeType *170DebugTranslation::translateImpl(DICompositeTypeAttr attr) {171 // TODO: Use distinct attributes to model this, once they have landed.172 // Depending on the tag, composite types must be distinct.173 bool isDistinct = false;174 switch (attr.getTag()) {175 case llvm::dwarf::DW_TAG_class_type:176 case llvm::dwarf::DW_TAG_enumeration_type:177 case llvm::dwarf::DW_TAG_structure_type:178 case llvm::dwarf::DW_TAG_union_type:179 isDistinct = true;180 }181 182 return getDistinctOrUnique<llvm::DICompositeType>(183 isDistinct, llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),184 translate(attr.getFile()), attr.getLine(), translate(attr.getScope()),185 translate(attr.getBaseType()), attr.getSizeInBits(),186 attr.getAlignInBits(),187 /*OffsetInBits=*/0,188 /*Flags=*/static_cast<llvm::DINode::DIFlags>(attr.getFlags()),189 getMDTupleOrNull(attr.getElements()),190 /*RuntimeLang=*/0, /*EnumKind*/ std::nullopt, /*VTableHolder=*/nullptr,191 /*TemplateParams=*/nullptr, /*Identifier=*/nullptr,192 /*Discriminator=*/nullptr,193 getExpressionAttrOrNull(attr.getDataLocation()),194 getExpressionAttrOrNull(attr.getAssociated()),195 getExpressionAttrOrNull(attr.getAllocated()),196 getExpressionAttrOrNull(attr.getRank()));197}198 199llvm::DIDerivedType *DebugTranslation::translateImpl(DIDerivedTypeAttr attr) {200 return llvm::DIDerivedType::get(201 llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),202 /*File=*/nullptr, /*Line=*/0,203 /*Scope=*/nullptr, translate(attr.getBaseType()), attr.getSizeInBits(),204 attr.getAlignInBits(), attr.getOffsetInBits(),205 attr.getDwarfAddressSpace(), /*PtrAuthData=*/std::nullopt,206 /*Flags=*/llvm::DINode::FlagZero, translate(attr.getExtraData()));207}208 209llvm::DIStringType *DebugTranslation::translateImpl(DIStringTypeAttr attr) {210 return llvm::DIStringType::get(211 llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),212 translate(attr.getStringLength()),213 getExpressionAttrOrNull(attr.getStringLengthExp()),214 getExpressionAttrOrNull(attr.getStringLocationExp()),215 attr.getSizeInBits(), attr.getAlignInBits(), attr.getEncoding());216}217 218llvm::DIFile *DebugTranslation::translateImpl(DIFileAttr attr) {219 return llvm::DIFile::get(llvmCtx, getMDStringOrNull(attr.getName()),220 getMDStringOrNull(attr.getDirectory()));221}222 223llvm::DILabel *DebugTranslation::translateImpl(DILabelAttr attr) {224 return llvm::DILabel::get(llvmCtx, translate(attr.getScope()),225 getMDStringOrNull(attr.getName()),226 translate(attr.getFile()), attr.getLine(),227 /*Column=*/0, /*IsArtificial=*/false,228 /*CoroSuspendIdx=*/std::nullopt);229}230 231llvm::DILexicalBlock *DebugTranslation::translateImpl(DILexicalBlockAttr attr) {232 return llvm::DILexicalBlock::getDistinct(llvmCtx, translate(attr.getScope()),233 translate(attr.getFile()),234 attr.getLine(), attr.getColumn());235}236 237llvm::DILexicalBlockFile *238DebugTranslation::translateImpl(DILexicalBlockFileAttr attr) {239 return llvm::DILexicalBlockFile::getDistinct(240 llvmCtx, translate(attr.getScope()), translate(attr.getFile()),241 attr.getDiscriminator());242}243 244llvm::DILocalScope *DebugTranslation::translateImpl(DILocalScopeAttr attr) {245 return cast<llvm::DILocalScope>(translate(DINodeAttr(attr)));246}247 248llvm::DIVariable *DebugTranslation::translateImpl(DIVariableAttr attr) {249 return cast<llvm::DIVariable>(translate(DINodeAttr(attr)));250}251 252llvm::DILocalVariable *253DebugTranslation::translateImpl(DILocalVariableAttr attr) {254 return llvm::DILocalVariable::get(255 llvmCtx, translate(attr.getScope()), getMDStringOrNull(attr.getName()),256 translate(attr.getFile()), attr.getLine(), translate(attr.getType()),257 attr.getArg(), static_cast<llvm::DINode::DIFlags>(attr.getFlags()),258 attr.getAlignInBits(),259 /*Annotations=*/nullptr);260}261 262llvm::DIGlobalVariable *263DebugTranslation::translateImpl(DIGlobalVariableAttr attr) {264 return llvm::DIGlobalVariable::getDistinct(265 llvmCtx, translate(attr.getScope()), getMDStringOrNull(attr.getName()),266 getMDStringOrNull(attr.getLinkageName()), translate(attr.getFile()),267 attr.getLine(), translate(attr.getType()), attr.getIsLocalToUnit(),268 attr.getIsDefined(), nullptr, nullptr, attr.getAlignInBits(), nullptr);269}270 271llvm::DINode *272DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) {273 DistinctAttr recursiveId = attr.getRecId();274 if (auto *iter = recursiveNodeMap.find(recursiveId);275 iter != recursiveNodeMap.end()) {276 return iter->second;277 }278 assert(!attr.getIsRecSelf() && "unbound DI recursive self reference");279 280 auto setRecursivePlaceholder = [&](llvm::DINode *placeholder) {281 recursiveNodeMap.try_emplace(recursiveId, placeholder);282 };283 284 llvm::DINode *result =285 TypeSwitch<DIRecursiveTypeAttrInterface, llvm::DINode *>(attr)286 .Case<DICompositeTypeAttr>([&](auto attr) {287 auto temporary = translateTemporaryImpl(attr);288 setRecursivePlaceholder(temporary.get());289 // Must call `translateImpl` directly instead of `translate` to290 // avoid handling the recursive interface again.291 auto *concrete = translateImpl(attr);292 temporary->replaceAllUsesWith(concrete);293 return concrete;294 })295 .Case<DISubprogramAttr>([&](auto attr) {296 auto temporary = translateTemporaryImpl(attr);297 setRecursivePlaceholder(temporary.get());298 // Must call `translateImpl` directly instead of `translate` to299 // avoid handling the recursive interface again.300 auto *concrete = translateImpl(attr);301 temporary->replaceAllUsesWith(concrete);302 return concrete;303 });304 305 assert(recursiveNodeMap.back().first == recursiveId &&306 "internal inconsistency: unexpected recursive translation stack");307 recursiveNodeMap.pop_back();308 309 return result;310}311 312llvm::DIScope *DebugTranslation::translateImpl(DIScopeAttr attr) {313 return cast<llvm::DIScope>(translate(DINodeAttr(attr)));314}315 316llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) {317 if (auto iter = distinctAttrToNode.find(attr.getId());318 iter != distinctAttrToNode.end())319 return cast<llvm::DISubprogram>(iter->second);320 321 llvm::DIScope *scope = translate(attr.getScope());322 llvm::DIFile *file = translate(attr.getFile());323 llvm::DIType *type = translate(attr.getType());324 llvm::DICompileUnit *compileUnit = translate(attr.getCompileUnit());325 326 // Check again after recursive calls in case this distinct node recurses back327 // to itself.328 if (auto iter = distinctAttrToNode.find(attr.getId());329 iter != distinctAttrToNode.end())330 return cast<llvm::DISubprogram>(iter->second);331 332 bool isDefinition = static_cast<bool>(attr.getSubprogramFlags() &333 LLVM::DISubprogramFlags::Definition);334 335 llvm::DISubprogram *node = getDistinctOrUnique<llvm::DISubprogram>(336 isDefinition, llvmCtx, scope, getMDStringOrNull(attr.getName()),337 getMDStringOrNull(attr.getLinkageName()), file, attr.getLine(), type,338 attr.getScopeLine(),339 /*ContainingType=*/nullptr, /*VirtualIndex=*/0,340 /*ThisAdjustment=*/0, llvm::DINode::FlagZero,341 static_cast<llvm::DISubprogram::DISPFlags>(attr.getSubprogramFlags()),342 compileUnit, /*TemplateParams=*/nullptr, /*Declaration=*/nullptr,343 getMDTupleOrNull(attr.getRetainedNodes()), nullptr,344 getMDTupleOrNull(attr.getAnnotations()));345 if (attr.getId())346 distinctAttrToNode.try_emplace(attr.getId(), node);347 return node;348}349 350llvm::DIModule *DebugTranslation::translateImpl(DIModuleAttr attr) {351 return llvm::DIModule::get(352 llvmCtx, translate(attr.getFile()), translate(attr.getScope()),353 getMDStringOrNull(attr.getName()),354 getMDStringOrNull(attr.getConfigMacros()),355 getMDStringOrNull(attr.getIncludePath()),356 getMDStringOrNull(attr.getApinotes()), attr.getLine(), attr.getIsDecl());357}358 359llvm::DINamespace *DebugTranslation::translateImpl(DINamespaceAttr attr) {360 return llvm::DINamespace::get(llvmCtx, translate(attr.getScope()),361 getMDStringOrNull(attr.getName()),362 attr.getExportSymbols());363}364 365llvm::DIImportedEntity *366DebugTranslation::translateImpl(DIImportedEntityAttr attr) {367 return llvm::DIImportedEntity::get(368 llvmCtx, attr.getTag(), translate(attr.getScope()),369 translate(attr.getEntity()), translate(attr.getFile()), attr.getLine(),370 getMDStringOrNull(attr.getName()), getMDTupleOrNull(attr.getElements()));371}372 373llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) {374 auto getMetadataOrNull = [&](Attribute attr) -> llvm::Metadata * {375 if (!attr)376 return nullptr;377 378 llvm::Metadata *metadata =379 llvm::TypeSwitch<Attribute, llvm::Metadata *>(attr)380 .Case([&](IntegerAttr intAttr) {381 return llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned(382 llvm::Type::getInt64Ty(llvmCtx), intAttr.getInt()));383 })384 .Case([&](LLVM::DIExpressionAttr expr) {385 return translateExpression(expr);386 })387 .Case([&](LLVM::DILocalVariableAttr local) {388 return translate(local);389 })390 .Case<>([&](LLVM::DIGlobalVariableAttr global) {391 return translate(global);392 })393 .Default(nullptr);394 return metadata;395 };396 return llvm::DISubrange::get(llvmCtx, getMetadataOrNull(attr.getCount()),397 getMetadataOrNull(attr.getLowerBound()),398 getMetadataOrNull(attr.getUpperBound()),399 getMetadataOrNull(attr.getStride()));400}401 402llvm::DICommonBlock *DebugTranslation::translateImpl(DICommonBlockAttr attr) {403 return llvm::DICommonBlock::get(llvmCtx, translate(attr.getScope()),404 translate(attr.getDecl()),405 getMDStringOrNull(attr.getName()),406 translate(attr.getFile()), attr.getLine());407}408 409llvm::DIGenericSubrange *410DebugTranslation::translateImpl(DIGenericSubrangeAttr attr) {411 auto getMetadataOrNull = [&](Attribute attr) -> llvm::Metadata * {412 if (!attr)413 return nullptr;414 415 llvm::Metadata *metadata =416 llvm::TypeSwitch<Attribute, llvm::Metadata *>(attr)417 .Case([&](LLVM::DIExpressionAttr expr) {418 return translateExpression(expr);419 })420 .Case([&](LLVM::DILocalVariableAttr local) {421 return translate(local);422 })423 .Case([&](LLVM::DIGlobalVariableAttr global) {424 return translate(global);425 })426 .Default(nullptr);427 return metadata;428 };429 return llvm::DIGenericSubrange::get(llvmCtx,430 getMetadataOrNull(attr.getCount()),431 getMetadataOrNull(attr.getLowerBound()),432 getMetadataOrNull(attr.getUpperBound()),433 getMetadataOrNull(attr.getStride()));434}435 436llvm::DISubroutineType *437DebugTranslation::translateImpl(DISubroutineTypeAttr attr) {438 // Concatenate the result and argument types into a single array.439 SmallVector<llvm::Metadata *> types;440 for (DITypeAttr type : attr.getTypes())441 types.push_back(translate(type));442 return llvm::DISubroutineType::get(443 llvmCtx, llvm::DINode::FlagZero, attr.getCallingConvention(),444 llvm::DITypeRefArray(llvm::MDNode::get(llvmCtx, types)));445}446 447llvm::DIType *DebugTranslation::translateImpl(DITypeAttr attr) {448 return cast<llvm::DIType>(translate(DINodeAttr(attr)));449}450 451llvm::DINode *DebugTranslation::translate(DINodeAttr attr) {452 if (!attr)453 return nullptr;454 // Check for a cached instance.455 if (llvm::DINode *node = attrToNode.lookup(attr))456 return node;457 458 llvm::DINode *node = nullptr;459 // Recursive types go through a dedicated handler. All other types are460 // dispatched directly to their specific handlers.461 if (auto recTypeAttr = dyn_cast<DIRecursiveTypeAttrInterface>(attr))462 if (recTypeAttr.getRecId())463 node = translateRecursive(recTypeAttr);464 465 if (!node)466 node = TypeSwitch<DINodeAttr, llvm::DINode *>(attr)467 .Case<DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr,468 DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr,469 DIGenericSubrangeAttr, DIGlobalVariableAttr,470 DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,471 DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,472 DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,473 DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(474 [&](auto attr) { return translateImpl(attr); });475 476 if (node && !node->isTemporary())477 attrToNode.insert({attr, node});478 return node;479}480 481//===----------------------------------------------------------------------===//482// Locations483//===----------------------------------------------------------------------===//484 485/// Translate the given location to an llvm debug location.486llvm::DILocation *DebugTranslation::translateLoc(Location loc,487 llvm::DILocalScope *scope) {488 if (!debugEmissionIsEnabled)489 return nullptr;490 return translateLoc(loc, scope, /*inlinedAt=*/nullptr);491}492 493llvm::DIExpression *494DebugTranslation::translateExpression(LLVM::DIExpressionAttr attr) {495 SmallVector<uint64_t, 1> ops;496 if (attr) {497 // Append operations their operands to the list.498 for (const DIExpressionElemAttr &op : attr.getOperations()) {499 ops.push_back(op.getOpcode());500 append_range(ops, op.getArguments());501 }502 }503 return llvm::DIExpression::get(llvmCtx, ops);504}505 506llvm::DIGlobalVariableExpression *507DebugTranslation::translateGlobalVariableExpression(508 LLVM::DIGlobalVariableExpressionAttr attr) {509 return llvm::DIGlobalVariableExpression::get(510 llvmCtx, translate(attr.getVar()), translateExpression(attr.getExpr()));511}512 513/// Translate the given location to an llvm DebugLoc.514llvm::DILocation *DebugTranslation::translateLoc(Location loc,515 llvm::DILocalScope *scope,516 llvm::DILocation *inlinedAt) {517 // LLVM doesn't have a representation for unknown.518 if (isa<UnknownLoc>(loc))519 return nullptr;520 521 // Check for a cached instance.522 auto existingIt = locationToLoc.find(std::make_tuple(loc, scope, inlinedAt));523 if (existingIt != locationToLoc.end())524 return existingIt->second;525 526 llvm::DILocation *llvmLoc = nullptr;527 if (auto callLoc = dyn_cast<CallSiteLoc>(loc)) {528 // For callsites, the caller is fed as the inlinedAt for the callee.529 auto *callerLoc = translateLoc(callLoc.getCaller(), scope, inlinedAt);530 // If the caller scope is not translatable, the overall callsite cannot be531 // represented in LLVM (the callee scope may not match the parent function).532 if (!callerLoc) {533 // If there is an inlinedAt scope (an outer caller), skip to that534 // directly. Otherwise, cannot translate.535 if (!inlinedAt)536 return nullptr;537 callerLoc = inlinedAt;538 }539 llvmLoc = translateLoc(callLoc.getCallee(), nullptr, callerLoc);540 // Fallback: Ignore callee if it has no debug scope.541 if (!llvmLoc)542 llvmLoc = callerLoc;543 544 } else if (auto fileLoc = dyn_cast<FileLineColLoc>(loc)) {545 // A scope of a DILocation cannot be null.546 if (!scope)547 return nullptr;548 llvmLoc =549 llvm::DILocation::get(llvmCtx, fileLoc.getLine(), fileLoc.getColumn(),550 scope, const_cast<llvm::DILocation *>(inlinedAt));551 552 } else if (auto fusedLoc = dyn_cast<FusedLoc>(loc)) {553 ArrayRef<Location> locations = fusedLoc.getLocations();554 555 // Check for a scope encoded with the location.556 if (auto scopedAttr =557 dyn_cast_or_null<LLVM::DILocalScopeAttr>(fusedLoc.getMetadata()))558 scope = translate(scopedAttr);559 560 // For fused locations, merge each of the nodes.561 llvmLoc = translateLoc(locations.front(), scope, inlinedAt);562 for (Location locIt : locations.drop_front()) {563 llvmLoc = llvm::DILocation::getMergedLocation(564 llvmLoc, translateLoc(locIt, scope, inlinedAt));565 }566 567 } else if (auto nameLoc = dyn_cast<NameLoc>(loc)) {568 llvmLoc = translateLoc(nameLoc.getChildLoc(), scope, inlinedAt);569 570 } else if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc)) {571 llvmLoc = translateLoc(opaqueLoc.getFallbackLocation(), scope, inlinedAt);572 } else {573 llvm_unreachable("unknown location kind");574 }575 576 locationToLoc.try_emplace(std::make_tuple(loc, scope, inlinedAt), llvmLoc);577 return llvmLoc;578}579 580/// Create an llvm debug file for the given file path.581llvm::DIFile *DebugTranslation::translateFile(StringRef fileName) {582 auto *&file = fileMap[fileName];583 if (file)584 return file;585 586 // Make sure the current working directory is up-to-date.587 if (currentWorkingDir.empty())588 llvm::sys::fs::current_path(currentWorkingDir);589 590 StringRef directory = currentWorkingDir;591 SmallString<128> dirBuf;592 SmallString<128> fileBuf;593 if (llvm::sys::path::is_absolute(fileName)) {594 // Strip the common prefix (if it is more than just "/") from current595 // directory and FileName for a more space-efficient encoding.596 auto fileIt = llvm::sys::path::begin(fileName);597 auto fileE = llvm::sys::path::end(fileName);598 auto curDirIt = llvm::sys::path::begin(directory);599 auto curDirE = llvm::sys::path::end(directory);600 for (; curDirIt != curDirE && *curDirIt == *fileIt; ++curDirIt, ++fileIt)601 llvm::sys::path::append(dirBuf, *curDirIt);602 if (std::distance(llvm::sys::path::begin(directory), curDirIt) == 1) {603 // Don't strip the common prefix if it is only the root "/" since that604 // would make LLVM diagnostic locations confusing.605 directory = StringRef();606 } else {607 for (; fileIt != fileE; ++fileIt)608 llvm::sys::path::append(fileBuf, *fileIt);609 directory = dirBuf;610 fileName = fileBuf;611 }612 }613 return (file = llvm::DIFile::get(llvmCtx, fileName, directory));614}615