[llvm] [llvm-debuginfo-analyzer] Add support for LLVM IR format. (PR #135440)
Carlos Alberto Enciso via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 4 21:59:16 PST 2025
================
@@ -0,0 +1,2309 @@
+//===-- LVIRReader.cpp ----------------------------------------------------===//
+//
+// 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 implements the LVIRReader class.
+// It supports LLVM text IR and bitcode format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVIRReader.h"
+#include "llvm/CodeGen/DebugHandlerBase.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SourceMgr.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "IRReader"
+
+// These flavours of DINodes are not implemented but technically possible:
+// DW_TAG_APPLE_property = 0x4200
+// DW_TAG_atomic_type = 0x0047
+// DW_TAG_common_block = 0x001a
+// DW_TAG_file_type = 0x0029
+// DW_TAG_friend = 0x002a
+// DW_TAG_generic_subrange = 0x0045
+// DW_TAG_immutable_type = 0x004b
+// DW_TAG_module = 0x001e
+// DW_TAG_variant_part = 0x0033
+
+// Create a logical element and setup the following information:
+// - Name, DWARF tag, line
+// - Collect any file information
+LVElement *LVIRReader::constructElement(const DINode *DN) {
+ dwarf::Tag Tag = DN->getTag();
+ LVElement *Element = createElement(Tag);
+ if (Element) {
+ Element->setTag(Tag);
+ addMD(DN, Element);
+
+ StringRef Name = getMDName(DN);
+ if (!Name.empty())
+ Element->setName(Name);
+
+ // Record any file information.
+ if (const DIFile *File = getMDFile(DN))
+ getOrCreateSourceID(File);
+ }
+
+ return Element;
+}
+
+void LVIRReader::mapFortranLanguage(unsigned DWLang) {
+ switch (DWLang) {
+ case dwarf::DW_LANG_Fortran77:
+ case dwarf::DW_LANG_Fortran90:
+ case dwarf::DW_LANG_Fortran95:
+ case dwarf::DW_LANG_Fortran03:
+ case dwarf::DW_LANG_Fortran08:
+ case dwarf::DW_LANG_Fortran18:
+ LanguageIsFortran = true;
+ break;
+ default:
+ LanguageIsFortran = false;
+ }
+}
+
+bool LVIRReader::includeMinimalInlineScopes() const {
+ return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly;
+}
+
+// For the given 'DIFile' generate an index 1-based to indicate the
+// source file where the logical element is declared.
+// The IR reader expects the indexes as 1-indexed.
+// Each compile unit, keeps track of the last assigned index.
+size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
+ if (!File)
+ return 0;
+
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateSourceID] DIFile\n";
+ File->dump();
+ });
+
+ addMD(File, CompileUnit);
+
+ LLVM_DEBUG({
+ dbgs() << "Directory: '" << File->getDirectory() << "'\n";
+ dbgs() << "Filename: '" << File->getFilename() << "'\n";
+ });
+ size_t FileIndex = 0;
+ LVCompileUnitFiles::iterator Iter = CompileUnitFiles.find(File);
+ if (Iter == CompileUnitFiles.end()) {
+ FileIndex = getFileIndex(CompileUnit);
+ std::string Directory(File->getDirectory());
+ if (Directory.empty())
+ Directory = std::string(CompileUnit->getCompilationDirectory());
+
+ std::string FullName;
+ raw_string_ostream Out(FullName);
+ Out << Directory << "/" << llvm::sys::path::filename(File->getFilename());
+ CompileUnit->addFilename(transformPath(FullName));
+ CompileUnitFiles.emplace(File, ++FileIndex);
+ updateFileIndex(CompileUnit, FileIndex);
+ } else {
+ FileIndex = Iter->second;
+ }
+
+ LLVM_DEBUG({ dbgs() << "FileIndex: " << FileIndex << "\n"; });
+ return FileIndex;
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, unsigned Line,
+ const DIFile *File) {
+ if (Line == 0)
+ return;
+
+ // After the scopes are created, the generic reader traverses the 'Children'
+ // and perform additional setting tasks (resolve types names, references,
+ // etc.). One of those tasks is select the correct string pool index based on
+ // the commmand line options: --attribute=filename or --attribute=pathname.
+ // As the 'Children' do not include logical lines, do that selection now,
+ // by calling 'setFilename' if the logical element is a line.
+ size_t FileID = getOrCreateSourceID(File);
+ if (Element->getIsLine())
+ Element->setFilename(CompileUnit->getFilename(FileID));
+ else
+ Element->setFilenameIndex(FileID);
+ Element->setLineNumber(Line);
+
+ LLVM_DEBUG({
+ dbgs() << "\n[addSourceLine]\n";
+ File->dump();
+ dbgs() << "FileIndex: " << Element->getFilenameIndex() << ", ";
+ dbgs() << "ID: " << Element->getID() << ", ";
+ dbgs() << "Kind: " << Element->kind() << ", ";
+ dbgs() << "Line: " << Element->getLineNumber() << ", ";
+ dbgs() << "Name: " << Element->getName() << "\n";
+ });
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIGlobalVariable *G) {
+ assert(G);
+ addSourceLine(Element, G->getLine(), G->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIImportedEntity *IE) {
+ assert(IE);
+ addSourceLine(Element, IE->getLine(), IE->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILabel *L) {
+ assert(L);
+ addSourceLine(Element, L->getLine(), L->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocalVariable *V) {
+ assert(V);
+ addSourceLine(Element, V->getLine(), V->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocation *DL) {
+ assert(DL);
+ addSourceLine(Element, DL->getLine(), DL->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIObjCProperty *Ty) {
+ assert(Ty);
+ addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DISubprogram *SP) {
+ assert(SP);
+ addSourceLine(Element, SP->getLine(), SP->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIType *Ty) {
+ assert(Ty);
+ addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addConstantValue(LVElement *Element,
+ const DIExpression *DIExpr) {
+ std::optional<DIExpression::SignedOrUnsignedConstant> Constant =
+ DIExpr->isConstant();
+ if (Constant == std::nullopt)
+ return;
+ std::stringstream Stream;
+ if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
+ int64_t Value = DIExpr->getElement(1);
+ if (Value < 0) {
+ Stream << "-";
+ Value = std::abs(Value);
+ }
+ Stream << hexString(Value, 2);
+ Element->setValue(Stream.str());
+ } else if (DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
+ Constant) {
+ uint64_t Value = DIExpr->getElement(1);
+ Stream << hexString(Value, 2);
+ Element->setValue(Stream.str());
+ }
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const ConstantInt *CI,
+ const DIType *Ty) {
+ addConstantValue(Element, CI->getValue(), Ty);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
+ const DIType *Ty) {
+ addConstantValue(Element, DebugHandlerBase::isUnsignedDIType(Ty), Val);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
+ bool Unsigned) {
+ addConstantValue(Element, llvm::APInt(64, Val, Unsigned), Unsigned);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Val,
+ const DIType *Ty) {
+ addConstantValue(Element, Val, DebugHandlerBase::isUnsignedDIType(Ty));
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Value,
+ bool Unsigned) {
+ SmallString<128> StringValue;
+ Value.toString(StringValue, /*Radix=*/16, /*Signed=*/!Unsigned,
+ /*formatAsCLiteral=*/true, /*UpperCase=*/false,
+ /*InsertSeparators=*/false);
+ Element->setValue(StringValue.str());
+}
+
+void LVIRReader::addString(LVElement *Element, StringRef String) {
+ Element->setValue(String);
+}
+
+void LVIRReader::processLocationGaps() {
+ if (options().getAttributeAnyLocation())
+ for (LVSymbol *Symbol : SymbolsWithLocations)
+ Symbol->fillLocationGaps();
+}
+
+void LVIRReader::processScopes() {
+ // - Calculate their location ranges.
+ // - Assign unique offset to the logical scopes, symbols and types,
+ // as the code the handles public names, expects them to have one.
+ // Use an arbitrary increment of 4.
+ // - Resolve any line pattern match.
+ // At this stage the compile unit and the root scopes they have the
+ // same offset, which is incorrect. Update the compile unit offset.
+ LVOffset Offset = 4;
+ auto SetOffset = [&](LVElement *Element) {
+ Element->setOffset(Offset);
+ Offset += OffsetIncrease;
+ };
+
+ std::function<void(LVScope *)> TraverseScope = [&](LVScope *Current) {
+ LVOffset Lower = Offset;
+ SetOffset(Current);
+ constructRange(Current);
+
+ if (const LVScopes *Scopes = Current->getScopes())
+ for (LVScope *Scope : *Scopes)
+ TraverseScope(Scope);
+
+ // Set an arbitrary 'Offset' for symbols and types.
+ if (const LVSymbols *Symbols = Current->getSymbols())
+ for (LVSymbol *Symbol : *Symbols)
+ SetOffset(Symbol);
+ if (const LVTypes *Types = Current->getTypes())
+ for (LVType *Type : *Types)
+ SetOffset(Type);
+
+ // Resolve any given pattern.
+ if (const LVLines *Lines = Current->getLines())
+ for (LVLine *Line : *Lines)
+ patterns().resolvePatternMatch(Line);
+
+ // Calculate contributions to the debug info.
+ LVOffset Upper = Offset;
+ if (options().getPrintSizes())
+ CompileUnit->addSize(Current, Lower, Upper);
+ };
+
+ TraverseScope(CompileUnit);
+}
+
+std::string LVIRReader::getRegisterName(LVSmall Opcode,
+ ArrayRef<uint64_t> Operands) {
+ // At this point we are operating on a logical view item, with no access
+ // to the underlying DWARF data used by LLVM.
+ // We do not support DW_OP_regval_type here.
+ if (Opcode == dwarf::DW_OP_regval_type)
+ return {};
+
+ if (Opcode == dwarf::DW_OP_regx || Opcode == dwarf::DW_OP_bregx) {
+ // If the following trace is enabled, its output will be intermixed
+ // with the logical view output, causing some confusion.
+ // Leaving it here, just for any specific needs.
+ // LLVM_DEBUG({
+ // dbgs() << "Printing Value: " << Operands[0] << " - "
+ // << ValueNameMap.getName(Operands[0]) << "\n";
+ // });
+ // Add an extra space for a better layout when printing locations.
+ return " " + ValueNameMap.getName(Operands[0]);
+ }
+
+ llvm_unreachable("We shouldn't actually have any other reg types here!");
+}
+
+LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
+ if (!Context)
+ return CompileUnit;
+
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScopeImpl] DIScope\n";
+ Context->dump();
+ });
+
+ // Check for an already seen scope parent.
+ if (LVScope *Parent = getScopeForSeenMD(Context))
+ return Parent;
+
+ // Traverse the scope hierarchy and construct the required scopes.
+ return traverseParentScope(Context);
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DILocation *DL) {
+ assert(DL && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScope] DILocation\n";
+ DL->dump();
+ });
+
+ return getParentScopeImpl(cast<DIScope>(DL->getScope()));
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DINode *DN) {
+ assert(DN && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScope] DINode\n";
+ DN->dump();
+ });
+
+ return getParentScopeImpl(getMDScope(DN));
+}
+
+// Traverse the scope hierarchy and create each node in the hierarchy.
+LVScope *LVIRReader::traverseParentScope(const DIScope *Context) {
+ if (!Context)
+ return CompileUnit;
+
+ LLVM_DEBUG({
+ dbgs() << "\n[traverseParentScope] DIScope\n";
+ Context->dump();
+ });
+
+ // Check if the metadata is already seen.
+ if (LVScope *Parent = getScopeForSeenMD(Context))
+ return Parent;
+
+ // Create the scope parent.
+ LVElement *Element = constructElement(Context);
+ if (Element) {
+ const DIScope *ParentContext = nullptr;
+ if (const auto *SP = dyn_cast<DISubprogram>(Context)) {
+ // Check for a specific 'Unit'.
+ if (DICompileUnit *CU = SP->getUnit())
+ ParentContext = getMDScope(SP->getDeclaration() ? CU : Context);
+ } else {
+ ParentContext = getMDScope(Context);
+ }
+ LVScope *Parent = traverseParentScope(ParentContext);
+ if (Parent) {
+ Parent->addElement(Element);
+ constructScope(Element, Context);
+ }
+ }
+
+ return static_cast<LVScope *>(Element);
+}
+
+// DW_TAG_base_type
+// DW_AT_name ("__ARRAY_SIZE_TYPE__")
+// DW_AT_byte_size (0x08)
+// DW_AT_encoding (DW_ATE_unsigned)
+LVType *LVIRReader::getIndexType() {
+ if (NodeIndexType)
+ return NodeIndexType;
+
+ // Construct an integer type to use for indexes.
+ NodeIndexType = static_cast<LVType *>(createElement(dwarf::DW_TAG_base_type));
+ if (NodeIndexType) {
+ NodeIndexType->setIsFinalized();
+ NodeIndexType->setName("__ARRAY_SIZE_TYPE__");
+ CompileUnit->addElement(NodeIndexType);
+ }
+
+ return NodeIndexType;
+}
+
+// Add accessibility info if available.
+void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
+ assert(Element && "Invalid logical element.");
+ LLVM_DEBUG({ dbgs() << "\n[addAccess] DIFlags " << Flags << "\n"; });
+
+ if ((Flags & DINode::FlagAccessibility) == DINode::FlagZero) {
+ LVScope *Parent = Element->getParentScope();
+ if (Parent->getIsClass())
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+ else if (Parent->getIsStructure() || Parent->getIsUnion())
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+ return;
+ }
+
+ if ((Flags & DINode::FlagAccessibility) == DINode::FlagProtected)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_protected);
+ else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPrivate)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+ else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+}
+
+// getFile()
+// DIScope
+// DILocation
+// DIVariable
+// DICommonBlock
+// DILabel
+// DIObjCProperty
+// DIImportedEntity
+// DIMacroFile
+const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
+ assert(MD && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDFile] MDNode\n";
+ MD->dump();
+ });
+
+ if (auto *T = dyn_cast<DIScope>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DILocation>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIVariable>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DICommonBlock>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DILabel>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIObjCProperty>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIImportedEntity>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIMacroFile>(MD))
+ return T->getFile();
+
+ return nullptr;
+}
+
+// getName()
+// DIScope
+// DIType
+// DISubprogram
+// DINamespace
+// DIModule
+// DITemplateParameter
+// DIVariable
+// DICommonBlock
+// DILabel
+// DIObjCProperty
+// DIImportedEntity
+// DIMacro
+// DIEnumerator
+StringRef LVIRReader::getMDName(const DINode *DN) const {
+ assert(DN && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDName] DINode\n";
+ DN->dump();
+ });
+
+ if (auto *T = dyn_cast<DIImportedEntity>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DICompositeType>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIDerivedType>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DILexicalBlockBase>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIEnumerator>(DN))
+ return T->getName();
+
+ if (/*auto *T = */ dyn_cast<DISubrange>(DN))
+ return StringRef();
+
+ if (auto *T = dyn_cast<DIVariable>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIScope>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DITemplateParameter>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DILabel>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIObjCProperty>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIMacro>(DN))
+ return T->getName();
+
+ assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+ return StringRef();
+}
+
+const DIScope *LVIRReader::getMDScope(const DINode *DN) const {
+ assert(DN && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDScope] DINode\n";
+ DN->dump();
+ });
+
+ if (dyn_cast<DIBasicType>(DN))
+ return getCUNode();
+
+ if (auto *T = dyn_cast<DINamespace>(DN)) {
+ // The scope for global namespaces is nullptr.
+ const DIScope *Context = T->getScope();
+ if (!Context)
+ Context = getCUNode();
+ return Context;
+ }
+
+ if (auto *T = dyn_cast<DIImportedEntity>(DN))
+ return T->getScope();
+
+ if (auto *T = dyn_cast<DIVariable>(DN))
+ return T->getScope();
+
+ if (auto *T = dyn_cast<DIScope>(DN))
+ return T->getScope();
+
+ assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+
+ // Assume the scope to be the compile unit.
+ return getCUNode();
+}
+
+//===----------------------------------------------------------------------===//
+// Logical elements construction using IR metadata.
+//===----------------------------------------------------------------------===//
+void LVIRReader::addTemplateParams(LVElement *Element,
+ const DINodeArray TParams) {
+ assert(Element && "Invalid logical element");
+ // assert(TParams && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[addTemplateParams] DINodeArray\n";
+ // TParams->dump();
+ for (const auto *Entry : TParams)
+ Entry->dump();
+ });
+
+ // Add template parameters.
+ for (const auto *Entry : TParams) {
+ if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(Entry))
+ constructTemplateTypeParameter(Element, TTP);
+ else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(Entry))
+ constructTemplateValueParameter(Element, TVP);
+ }
+}
+
+// DISubprogram
+void LVIRReader::applySubprogramAttributes(LVScope *Function,
+ const DISubprogram *SP,
+ bool SkipSPAttributes) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[applySubprogramAttributes] DISubprogram\n";
+ SP->dump();
+ });
+
+ // If -fdebug-info-for-profiling is enabled, need to emit the subprogram
+ // and its source location.
+ bool SkipSPSourceLocation =
+ SkipSPAttributes && !getCUNode()->getDebugInfoForProfiling();
+ if (!SkipSPSourceLocation)
+ if (applySubprogramDefinitionAttributes(Function, SP, SkipSPAttributes))
+ return;
+
+ if (!SkipSPSourceLocation)
+ addSourceLine(Function, SP);
+
+ // Skip the rest of the attributes under -gmlt to save space.
+ if (SkipSPAttributes)
+ return;
+
+ DITypeRefArray Args;
+ if (const DISubroutineType *SPTy = SP->getType())
+ Args = SPTy->getTypeArray();
+
+ // Construct subprogram return type.
+ if (Args.size()) {
+ LVElement *ElementType = getOrCreateType(Args[0]);
+ Function->setType(ElementType);
+ }
+
+ // Add virtuality info if available.
+ Function->setVirtualityCode(SP->getVirtuality());
+
+ if (!SP->isDefinition()) {
+ // Add arguments. Do not add arguments for subprogram definition. They will
+ // be handled while processing variables.
+ constructSubprogramArguments(Function, Args);
+ }
+
+ if (SP->isArtificial())
+ Function->setIsArtificial();
+
+ if (!SP->isLocalToUnit())
+ Function->setIsExternal();
+
+ // Add accessibility info if available.
+ addAccess(Function, SP->getFlags());
+}
+
+// DISubprogram
+bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
+ const DISubprogram *SP,
+ bool Minimal) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[applySubprogramDefinitionAttributes] DISubprogram\n";
+ SP->dump();
+ });
+
+ LVScope *Reference = nullptr;
+ StringRef DeclLinkageName;
+ if (const DISubprogram *SPDecl = SP->getDeclaration()) {
+ if (!Minimal) {
+ DITypeRefArray DeclArgs, DefinitionArgs;
+ DeclArgs = SPDecl->getType()->getTypeArray();
+ DefinitionArgs = SP->getType()->getTypeArray();
+
+ // The element zero in 'DefinitionArgs' and 'DeclArgs' arrays is
+ // the subprogram return type. A 'void' return does not have a
+ // type and it is represented by a 'nullptr' value.
+ // For the given test case and its IR:
+ //
+ // 1 struct Bar {
+ // 2 bool foo(int a);
+ // 3 };
+ // 4
+ // 5 bool Bar::foo(int a) {
+ // 6 return false;
+ // 7 }
+ //
+ // !10 = !DISubprogram(name: "foo", line: 5, type: !14,
+ // spFlags: DISPFlagDefinition)
+ // !13 = !DISubprogram(name: "foo", line: 2, type: !14, spFlags: 0)
+ // !14 = !DISubroutineType(types: !15)
+ // !15 = !{!16, !17, !18}
+ // !16 = !DIBasicType(name: "bool", ...)
+ //
+ // '!15' represents both 'DefinitionArgs' and 'DeclArgs' arrays.
+ // For cases where they have a different metadata node, use the
+ // type from the 'DefinitionArgs' array as the correct type.
+ if (DeclArgs.size() && DefinitionArgs.size())
+ if (DefinitionArgs[0] != nullptr && DeclArgs[0] != DefinitionArgs[0]) {
+ LVElement *ElementType = getOrCreateType(DefinitionArgs[0]);
+ Function->setType(ElementType);
+ }
+
+ Reference = getScopeForSeenMD(SPDecl);
+ assert(Reference && "Scope should've already been constructed.");
+ // Look at the Decl's linkage name only if we emitted it.
+ if (useAllLinkageNames())
+ DeclLinkageName = SPDecl->getLinkageName();
+ unsigned DeclID = getOrCreateSourceID(SPDecl->getFile());
+ unsigned DefID = getOrCreateSourceID(SP->getFile());
+ if (DeclID != DefID)
+ Function->setFilenameIndex(DefID);
+
+ if (SP->getLine() != SPDecl->getLine())
+ Function->setLineNumber(SP->getLine());
+ }
+ }
+
+ // Add function template parameters.
+ addTemplateParams(Function, SP->getTemplateParams());
+
+ // Add the linkage name if we have one and it isn't in the Decl.
+ StringRef LinkageName = SP->getLinkageName();
+ assert(((LinkageName.empty() || DeclLinkageName.empty()) ||
+ LinkageName == DeclLinkageName) &&
+ "decl has a linkage name and it is different");
+ if (DeclLinkageName.empty() && (useAllLinkageNames()))
+ // Always emit it for abstract subprograms.
+ Function->setLinkageName(LinkageName);
+
+ if (!Reference)
+ return false;
+
+ // Refer to the function declaration where all the other attributes will be
+ // found.
+ Function->setReference(Reference);
+ Function->setHasReferenceSpecification();
+
+ return true;
+}
+
+// DICompositeType
+void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
+ const DICompositeType *CTy) {
+ assert(Aggregate && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructAggregate] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Aggregate->getIsFinalized())
+ return;
+ Aggregate->setIsFinalized();
+
+ dwarf::Tag Tag = Aggregate->getTag();
+
+ // Add template parameters to a class, structure or union types.
+ if (Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
+ Tag == dwarf::DW_TAG_union_type)
+ addTemplateParams(Aggregate, CTy->getTemplateParams());
+
+ // Add elements to aggregate type.
+ for (const auto *Member : CTy->getElements()) {
+ if (!Member)
+ continue;
+ LLVM_DEBUG({
+ dbgs() << "\nAggregate Element\n";
+ Member->dump();
+ });
+ if (const auto *SP = dyn_cast<DISubprogram>(Member))
+ getOrCreateSubprogram(SP);
+ else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Member)) {
+ dwarf::Tag Tag = Member->getTag();
+ if (Tag == dwarf::DW_TAG_member || Tag == dwarf::DW_TAG_variable) {
+ if (DT->isStaticMember())
+ getOrCreateStaticMember(Aggregate, DT);
+ else
+ getOrCreateMember(Aggregate, DT);
+ } else {
+ getOrCreateType(DT, Aggregate);
+ }
+ }
+ }
+}
+
+// DICompositeType
+void LVIRReader::constructArray(LVScopeArray *Array,
+ const DICompositeType *CTy) {
+ assert(Array && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructArray] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Array->getIsFinalized())
+ return;
+ Array->setIsFinalized();
+
+ if (LVElement *BaseType = getOrCreateType(CTy->getBaseType()))
+ Array->setType(BaseType);
+
+ // Get an anonymous type for index type.
+ LVType *IndexType = getIndexType();
+
+ // Add subranges to array type.
+ DINodeArray Entries = CTy->getElements();
+ for (DINode *DN : Entries) {
+ if (auto *SR = dyn_cast_or_null<DINode>(DN)) {
+ if (SR->getTag() == dwarf::DW_TAG_subrange_type)
+ constructSubrange(Array, cast<DISubrange>(SR), IndexType);
+ else if (SR->getTag() == dwarf::DW_TAG_generic_subrange)
+ constructGenericSubrange(Array, cast<DIGenericSubrange>(SR), IndexType);
+ }
+ }
+}
+
+// DICompositeType
+void LVIRReader::constructEnum(LVScopeEnumeration *Enumeration,
+ const DICompositeType *CTy) {
+ assert(Enumeration && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructEnum] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Enumeration->getIsFinalized())
+ return;
+ Enumeration->setIsFinalized();
+
+ const DIType *Ty = CTy->getBaseType();
+ bool IsUnsigned = Ty && DebugHandlerBase::isUnsignedDIType(Ty);
+
+ if (LVElement *BaseType = getOrCreateType(Ty))
+ Enumeration->setType(BaseType);
+
+ if (CTy->getFlags() & DINode::FlagEnumClass)
+ Enumeration->setIsEnumClass();
+
+ // Add enumerators to enumeration type.
+ DINodeArray Entries = CTy->getElements();
+ for (const DINode *DN : Entries) {
+ if (auto *Enum = dyn_cast_or_null<DIEnumerator>(DN)) {
+ if (LVElement *Enumerator = constructElement(Enum)) {
+ Enumerator->setIsFinalized();
+ Enumeration->addElement(Enumerator);
+ addConstantValue(Enumerator, Enum->getValue(), IsUnsigned);
+ }
+ }
+ }
+}
+
+void LVIRReader::constructGenericSubrange(LVScopeArray *Array,
+ const DIGenericSubrange *GSR,
+ LVType *IndexType) {
+ assert(Array && "Invalid logical element");
+ assert(GSR && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructGenericSubrange] DIGenericSubrange\n";
+ GSR->dump();
+ });
+
+ LLVM_DEBUG({ dbgs() << "\nNot implemented\n"; });
+}
+
+// DIImportedEntity
+void LVIRReader::constructImportedEntity(LVElement *Element,
+ const DIImportedEntity *IE) {
+ assert(Element && "Invalid logical element");
+ assert(IE && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructImportedEntity] DIImportedEntity\n";
+ IE->dump();
+ });
+
+ if (LVElement *Import = constructElement(IE)) {
+ Import->setIsFinalized();
+ addSourceLine(Import, IE);
+ LVScope *Parent = getParentScope(IE);
+ Parent->addElement(Import);
+
+ const DINode *Entity = IE->getEntity();
+ LVElement *Target = getElementForSeenMD(Entity);
+ if (!Target) {
+ if (const auto *Ty = dyn_cast<DIType>(Entity))
+ Target = getOrCreateType(Ty);
+ else if (const auto *SP = dyn_cast<DISubprogram>(Entity))
+ Target = getOrCreateSubprogram(SP);
+ else if (const auto *NS = dyn_cast<DINamespace>(Entity))
+ Target = getOrCreateNamespace(NS);
+ else if (const auto *M = dyn_cast<DIModule>(Entity))
+ Target = getOrCreateScope(M);
+ }
+ Import->setType(Target);
+ }
+}
+
+LVScope *LVIRReader::getOrCreateInlinedScope(LVScope *AbstractScope,
+ const DILocation *DL) {
+ assert(AbstractScope && "Invalid logical element");
+ assert(DL && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateInlinedScope] DILocation\n";
+ DL->dump();
+ });
+
+ const DILocation *InlinedAt = DL->getInlinedAt();
+ DILocalScope *Context = DL->getScope();
+ LLVM_DEBUG({
+ dbgs() << "\nParent Scope:\n";
+ AbstractScope->getParentScope()->dump();
+ dbgs() << "\nOriginScope:\n";
+ AbstractScope->dump();
+ dbgs() << "\nInlinedAt:\n";
+ InlinedAt->dump();
+ dbgs() << "\nContext:\n";
+ Context->dump();
+ });
+
+ dwarf::Tag Tag = AbstractScope->getTag();
+ if (AbstractScope->getIsFunction() || AbstractScope->getIsInlinedFunction()) {
+ Tag = dwarf::DW_TAG_inlined_subroutine;
+ AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
+ }
+ LVScope *InlinedScope = static_cast<LVScope *>(createElement(Tag));
+ if (InlinedScope) {
+ addInlinedScope(AbstractScope, InlinedAt, InlinedScope);
+ InlinedScope->setTag(Tag);
+ InlinedScope->setIsFinalized();
+ InlinedScope->setName(AbstractScope->getName());
+ InlinedScope->setType(AbstractScope->getType());
+
+ InlinedScope->setCallLineNumber(InlinedAt->getLine());
+ InlinedScope->setCallFilenameIndex(
+ getOrCreateSourceID(InlinedAt->getFile()));
+
+ InlinedScope->setReference(AbstractScope);
+ InlinedScope->setHasReferenceAbstract();
+
+ // Get or create the parent scope for the inlined subprogram.
+ LVScope *Parent =
+ InlinedScope->getIsLexicalBlock()
+ ? getInlinedScope(AbstractScope->getParentScope(), InlinedAt)
+ : getOrCreateScope(InlinedAt->getScope());
+ assert(Parent && "Parent scope is NULL.");
+ Parent->addElement(InlinedScope);
+ }
+
+ return InlinedScope;
+}
+
+LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *Parent,
+ const DILocation *DL) {
+ assert(Parent && "Invalid logical element");
+ assert(DL && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
+ DL->dump();
+ dbgs() << "Parent Logical Scope:\n";
+ Parent->dump();
+ });
+
+ const DILocation *InlinedAt = DL->getInlinedAt();
+ if (!InlinedAt)
+ return nullptr;
+
+ DILocalScope *Context = DL->getScope();
+ if (!Context)
+ return nullptr;
+
+ // Check if we have seen the scope.
+ LVScope *AbstractScope = getScopeForSeenMD(Context);
+ if (!AbstractScope) {
+ // Create the 'abstract' scope.
+ if (isa<DISubprogram>(Context)) {
+ AbstractScope =
+ getOrCreateSubprogram(static_cast<DISubprogram *>(Context));
+ AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
+ } else if (isa<DILexicalBlock>(Context)) {
+ AbstractScope = getOrCreateScope(static_cast<DIScope *>(Context));
+ }
+ LLVM_DEBUG({
+ dbgs() << "\nParent Scope:\n";
+ AbstractScope->getParentScope()->dump();
+ dbgs() << "Abstract Scope:\n";
+ AbstractScope->dump();
+ });
+
+ // Create the 'inlined' scope.
+ LVScope *InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
+ assert(InlinedScope && "InlinedScope is null.");
+ LLVM_DEBUG({
+ dbgs() << "\nParent Scope:\n";
+ InlinedScope->getParentScope()->dump();
+ dbgs() << "\nInlined Scope:\n";
+ InlinedScope->dump();
+ });
+ }
+
+ return AbstractScope;
+}
+
+void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
+ Instruction &I,
+ bool &GenerateLineBeforePrologue) {
+ assert(Scope && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructLine] Instruction\n";
+ I.dump();
+ dbgs() << "Logical Scope:\n";
+ Scope->dump();
+ });
+
+ auto AddDebugLine = [&](LVScope *Parent, unsigned ID) -> LVLine * {
+ assert(Parent && "Invalid logical element");
+ assert(ID == Metadata::DILocationKind && "Invalid Metadata Object");
+
+ LVLine *Line = createLineDebug();
+ if (Line) {
+ Parent->addElement(Line);
+
+ Line->setIsFinalized();
+ Line->setAddress(CurrentOffset);
+
+ // FIXME: How to get discrimination flags:
+ // IsStmt, BasicBlock, EndSequence, EpilogueBegin, PrologueEnd.
+
+ // Add mapping for this debug line.
+ CompileUnit->addMapping(Line, SectionIndex);
+
+ // Replicate the DWARF reader functionality of adding a linkage
+ // name to a function with ranges (logical lines), regardless if
+ // the declaration has already one.
+ if (!Parent->getLinkageNameIndex() &&
+ Parent->getHasReferenceSpecification()) {
+ Parent->setLinkageName(Parent->getReference()->getLinkageName());
+ }
+ GenerateLineBeforePrologue = false;
+ }
+
+ return Line;
+ };
+
+ auto AddAssemblerLine = [&](LVScope *Parent) {
+ assert(Parent && "Invalid logical element");
+
+ static const char *WhiteSpace = " \t\n\r\f\v";
+ static std::string Metadata("metadata ");
+
+ auto RemoveAll = [](std::string &Input, std::string &Pattern) {
+ std::string::size_type Len = Pattern.length();
+ for (std::string::size_type Index = Input.find(Pattern);
+ Index != std::string::npos; Index = Input.find(Pattern))
+ Input.erase(Index, Len);
+ };
+
+ std::string InstructionText;
+ raw_string_ostream Stream(InstructionText);
+ Stream << I;
+ // Remove the 'metadata ' pattern from the instruction text.
+ RemoveAll(InstructionText, Metadata);
+ std::string_view Text(InstructionText);
+ const auto pos(Text.find_first_not_of(WhiteSpace));
+ Text.remove_prefix(std::min(pos, Text.length()));
+
+ // Create an instruction line at the given scope.
+ if (LVLineAssembler *Line = createLineAssembler()) {
+ Line->setIsFinalized();
+ Line->setAddress(CurrentOffset);
+ Line->setName(Text);
+ Parent->addElement(Line);
+ }
+ };
+
+ LVScope *Parent = Scope;
+ if (const DebugLoc DbgLoc = I.getDebugLoc()) {
+ const DILocation *DL = DbgLoc.get();
+ Parent = getParentScope(DL);
+ if (const DILocation *InlinedAt = DL->getInlinedAt())
+ Parent = getInlinedScope(Parent, InlinedAt);
+
+ LLVM_DEBUG({
+ dbgs() << "\n[constructLine] DILocation\n";
+ DL->dump();
+ });
+
+ if (options().getPrintLines() && DL->getLine()) {
+ if (LVLine *Line = AddDebugLine(Parent, DL->getMetadataID())) {
+ addMD(DL, Line);
+ addSourceLine(Line, DL);
+ GenerateLineBeforePrologue = false;
+ }
+ }
+ }
+
+ // Generate a logical line before the function prologue.
+ if (options().getPrintLines() && GenerateLineBeforePrologue) {
+ if (LVLine *Line = AddDebugLine(Parent, Metadata::DILocationKind)) {
+ addSourceLine(Line, SP);
+ GenerateLineBeforePrologue = false;
+ }
+ }
+
+ // Create assembler line.
+ if (options().getPrintInstructions())
+ AddAssemblerLine(Parent);
+}
+
+LVSymbol *LVIRReader::getOrCreateMember(LVScope *Aggregate,
+ const DIDerivedType *DT) {
+ assert(Aggregate && "Invalid logical element");
+ assert(DT && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateMember] DIDerivedType\n";
+ DT->dump();
+ });
+
+ LVSymbol *Member = getSymbolForSeenMD(DT);
+ if (Member && Member->getIsFinalized())
+ return Member;
+
+ if (!options().getPrintSymbols()) {
+ // Just create the symbol type.
+ getOrCreateType(DT->getBaseType());
+ return nullptr;
+ }
+
+ if (!Member)
+ Member = static_cast<LVSymbol *>(getOrCreateType(DT, Aggregate));
+ if (Member) {
+ Member->setIsFinalized();
+ addSourceLine(Member, DT);
+ if (DT->getTag() == dwarf::DW_TAG_inheritance && DT->isVirtual()) {
+ Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0,
+ /*HighPC=*/-1, /*SectionOffset=*/0,
+ /*OffsetOnEntry=*/0);
+ } else {
+ uint64_t OffsetInBytes = 0;
+
+ bool IsBitfield = DT->isBitField();
+ if (IsBitfield) {
+ Member->setBitSize(DT->getSizeInBits());
+ } else {
+ // This is not a bitfield.
+ OffsetInBytes = DT->getOffsetInBits() / 8;
+ }
+
+ if (DwarfVersion <= 2) {
+ // DW_AT_data_member_location:
+ // DW_FORM_data1, DW_OP_plus_uconst, DW_FORM_udata, OffsetInBytes
+ Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0,
+ /*HighPC=*/-1, /*SectionOffset=*/0,
+ /*OffsetOnEntry=*/0);
+ Member->addLocationOperands(dwarf::DW_OP_plus_uconst, {OffsetInBytes});
+ } else if (!IsBitfield || DwarfVersion < 4) {
+ // DW_AT_data_member_location:
+ // DW_FORM_udata, OffsetInBytes
+ Member->addLocationConstant(dwarf::DW_AT_data_member_location,
+ OffsetInBytes,
+ /*OffsetOnEntry=*/0);
+ }
+ }
+ }
+
+ // Add accessibility info if available.
+ if (!DT->isStaticMember())
+ addAccess(Member, DT->getFlags());
+
+ if (DT->isVirtual())
+ Member->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual);
+
+ if (DT->isArtificial())
+ Member->setIsArtificial();
+
+ return Member;
+}
+
+// DIBasicType
+// DICommonBlock
+// DICompileUnit
+// DICompositeType
+// DIDerivedType
+// DIFile
+// DILexicalBlock
+// DILexicalBlockFile
+// DIModule
+// DINamespace
+// DISubprogram
+// DISubroutineType
+// DIStringType
+void LVIRReader::constructScope(LVElement *Element, const DIScope *Context) {
+ assert(Element && "Invalid logical element");
+ assert(Context && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructScope] DIScope\n";
+ Context->dump();
+ });
+
+ if (Context && isa<DICompositeType>(Context)) {
+ const DICompositeType *CTy = cast<DICompositeType>(Context);
+ constructType(static_cast<LVScope *>(Element), CTy);
+ } else if (Context && isa<DIDerivedType>(Context)) {
+ const DIDerivedType *DT = cast<DIDerivedType>(Context);
+ constructType(Element, DT);
+ } else if (Context && isa<DISubprogram>(Context)) {
+ const DISubprogram *SP = cast<DISubprogram>(Context);
+ getOrCreateSubprogram(static_cast<LVScope *>(Element), SP);
+ } else if (Context && isa<DINamespace>(Context)) {
+ Element->setIsFinalized();
+ } else if (Context && isa<DILexicalBlock>(Context)) {
+ Element->setIsFinalized();
+ }
+}
+
+LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate,
+ const DIDerivedType *DT) {
+ assert(Aggregate && "Invalid logical element");
+ assert(DT && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateStaticMember] DIDerivedType\n";
+ DT->dump();
+ });
+
+ LVSymbol *Member = getSymbolForSeenMD(DT);
+ if (Member && Member->getIsFinalized())
+ return Member;
+
+ if (!options().getPrintSymbols()) {
+ // Just create the symbol type.
+ getOrCreateType(DT->getBaseType());
+ return nullptr;
+ }
+
+ if (!Member)
+ Member = static_cast<LVSymbol *>(getOrCreateType(DT, Aggregate));
+ if (Member) {
+ Member->setIsFinalized();
+ addSourceLine(Member, DT);
+ Member->setIsExternal();
+ }
+
+ return Member;
+}
+
+// DISubprogram
+LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP) {
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
+ SP->dump();
+ });
+
+ LVScope *Function = getScopeForSeenMD(SP);
+ if (Function && Function->getIsFinalized())
+ return Function;
+
+ if (!Function)
+ Function = static_cast<LVScope *>(constructElement(SP));
+ if (Function) {
+ // For both member functions (declaration and definition) its parent
+ // is the containing class. The 'definition' points back to its
+ // 'declaration' via the 'getDeclaration' return value.
+ LVScope *Parent = SP->getDeclaration()
+ ? SP->isLocalToUnit() || SP->isDefinition()
+ ? CompileUnit
+ : getParentScope(SP)->getParentScope()
+ : getParentScope(SP);
+ // The 'getParentScope' traverses the scope hierarchy and it creates
+ // the scope chain and any associated types.
+ // Check that the 'Function' is not already in the parent.
+ if (!Function->getParent())
+ Parent->addElement(Function);
+
+ getOrCreateSubprogram(Function, SP, includeMinimalInlineScopes());
+ }
+
+ return Function;
+}
+
+// DISubprogram
+LVScope *LVIRReader::getOrCreateSubprogram(LVScope *Function,
+ const DISubprogram *SP,
+ bool Minimal) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
+ SP->dump();
+ });
+
+ if (Function->getIsFinalized())
+ return Function;
+ Function->setIsFinalized();
+
+ // Get 'declaration' node in order to generate the DW_AT_specification.
+ if (const DISubprogram *SPDecl = SP->getDeclaration()) {
+ if (!Minimal) {
+ // Build the declaration now to ensure it precedes the definition.
+ getOrCreateSubprogram(SPDecl);
+ }
+ }
+
+ // Check for additional retained nodes.
+ for (const DINode *DN : SP->getRetainedNodes()) {
+ if (const auto *IE = dyn_cast<DIImportedEntity>(DN))
+ constructImportedEntity(Function, IE);
+ else if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(DN))
+ constructTemplateTypeParameter(Function, TTP);
+ else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(DN))
+ constructTemplateValueParameter(Function, TVP);
+ }
+
+ applySubprogramAttributes(Function, SP);
+
+ // Check if we are dealing with the Global Init/Cleanup Function.
+ if (SP->isArtificial() && SP->isLocalToUnit() && SP->isDefinition() &&
+ SP->getName().empty())
+ Function->setName(SP->getLinkageName());
+
+ return Function;
+}
+
+void LVIRReader::constructSubprogramArguments(LVScope *Function,
+ const DITypeRefArray Args) {
+ assert(Function && "Invalid logical element");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructSubprogramArguments] DITypeRefArray\n";
+ for (unsigned i = 1, N = Args.size(); i < N; ++i) {
+ if (const DIType *Ty = Args[i])
+ Ty->dump();
+ }
+ });
+
+ for (unsigned I = 1, N = Args.size(); I < N; ++I) {
+ const DIType *Ty = Args[I];
+ LVElement *Parameter = nullptr;
+ if (Ty) {
+ // Create a formal parameter.
+ LVElement *ParameterType = getOrCreateType(Ty);
+ Parameter = createElement(dwarf::DW_TAG_formal_parameter);
+ if (Parameter) {
+ Parameter->setType(ParameterType);
+ if (Ty->isArtificial())
+ Parameter->setIsArtificial();
+ }
+ } else {
+ // Add an unspecified parameter.
+ Parameter = createElement(dwarf::DW_TAG_unspecified_parameters);
+ }
+ if (Parameter) {
+ Function->addElement(Parameter);
+ Parameter->setIsFinalized();
+ }
+ }
+}
+
+// DISubrange
+void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
+ LVType *IndexType) {
+ assert(Array && "Invalid logical element");
+ assert(GSR && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructSubrange] DISubrange\n";
+ GSR->dump();
+ });
+
+ // The DISubrange can be shared between different arrays, when they are
+ // the same. We need to create independent logical elements for each one,
+ // as they are going to be added to different arrays.
+ if (LVTypeSubrange *Subrange =
+ static_cast<LVTypeSubrange *>(constructElement(GSR))) {
+ Subrange->setIsFinalized();
+ Array->addElement(Subrange);
+ Subrange->setType(IndexType);
+
+ int64_t Count = -1;
+ // If Subrange has a Count field, use it.
+ // Otherwise, if it has an upperboud, use (upperbound - lowerbound + 1),
+ // where lowerbound is from the LowerBound field of the Subrange,
+ // or the language default lowerbound if that field is unspecified.
+ if (auto *CI = dyn_cast_if_present<ConstantInt *>(GSR->getCount()))
+ Count = CI->getSExtValue();
+ else if (auto *UI =
+ dyn_cast_if_present<ConstantInt *>(GSR->getUpperBound())) {
+ // Fortran uses 1 as the default lowerbound; other languages use 0.
+ int64_t Lowerbound = (moduleIsInFortran()) ? 1 : 0;
+ auto *LI = dyn_cast_if_present<ConstantInt *>(GSR->getLowerBound());
+ Lowerbound = (LI) ? LI->getSExtValue() : Lowerbound;
+ Count = UI->getSExtValue() - Lowerbound + 1;
+ }
+
+ if (Count == -1)
+ Count = 0;
+ Subrange->setCount(Count);
+ }
+}
+
+// DITemplateTypeParameter
+void LVIRReader::constructTemplateTypeParameter(
+ LVElement *Element, const DITemplateTypeParameter *TTP) {
+ assert(Element && "Invalid logical element");
+ assert(TTP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructTemplateTypeParameter] DITemplateTypeParameter\n";
+ TTP->dump();
+ });
+
+ // The DITemplateTypeParameter can be shared between different subprogram
+ // in their DITemplateParameterArray describing the template parameters.
+ // We need to create independent logical elements for each one, as they are
+ // going to be added to different function.
+ if (LVElement *Parameter = constructElement(TTP)) {
+ Parameter->setIsFinalized();
+ // Add element to parent (always the given Element).
+ LVScope *Parent = static_cast<LVScope *>(Element);
+ Parent->addElement(Parameter);
+ // Mark the parent as template.
+ Parent->setIsTemplate();
+
+ // Add the type if it exists, it could be void and therefore no type.
+ if (const DIType *Ty = TTP->getType()) {
+ LVElement *Type = getElementForSeenMD(Ty);
+ if (!Type)
+ Type = getOrCreateType(Ty);
+ Parameter->setType(Type);
+ }
+ }
+}
+
+// DITemplateValueParameter
+void LVIRReader::constructTemplateValueParameter(
+ LVElement *Element, const DITemplateValueParameter *TVP) {
+ assert(Element && "Invalid logical element");
+ assert(TVP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructTemplateValueParameter] DITemplateValueParameter\n";
+ TVP->dump();
+ });
+
+ // The DITemplateValueParameter can be shared between different subprogram
+ // in their DITemplateParameterArray describing the template parameters.
+ // We need to create independent logical elements for each one, as they are
+ // going to be added to different function.
+ if (LVElement *Parameter = constructElement(TVP)) {
+ Parameter->setIsFinalized();
+ // Add element to parent (always the given Element).
+ LVScope *Parent = static_cast<LVScope *>(Element);
+ Parent->addElement(Parameter);
+ // Mark the parent as template.
+ Parent->setIsTemplate();
+
+ // Add the type if there is one, template template and template parameter
+ // packs will not have a type.
+ if (TVP->getTag() == dwarf::DW_TAG_template_value_parameter) {
+ LVElement *Type = getOrCreateType(TVP->getType());
+ Parameter->setType(Type);
+ }
+ if (Metadata *Value = TVP->getValue()) {
+ if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Value))
+ addConstantValue(Parameter, CI, TVP->getType());
+ else if (GlobalValue *GV = mdconst::dyn_extract<GlobalValue>(Value)) {
+ // We cannot describe the location of dllimport'd entities: the
+ // computation of their address requires loads from the IAT.
+ if (!GV->hasDLLImportStorageClass()) {
+ }
+ } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_template_param) {
+ assert(isa<MDString>(Value));
+ // Add the value for dwarf::DW_AT_GNU_template_name.
+ Parameter->setValue(cast<MDString>(Value)->getString());
+ } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
+ addTemplateParams(Parameter, cast<MDTuple>(Value));
+ }
+ }
+ }
+}
+
+// DICompositeType
+// DW_TAG_array_type
+// DW_TAG_class_type
+// DW_TAG_enumeration_type
+// DW_TAG_structure_type
+// DW_TAG_union_type
+void LVIRReader::constructType(LVScope *Scope, const DICompositeType *CTy) {
+ assert(Scope && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructType] DICompositeType\n";
+ CTy->dump();
+ });
+
+ dwarf::Tag Tag = Scope->getTag();
+ switch (Tag) {
+ case dwarf::DW_TAG_array_type:
+ constructArray(static_cast<LVScopeArray *>(Scope), CTy);
+ break;
+ case dwarf::DW_TAG_enumeration_type:
+ constructEnum(static_cast<LVScopeEnumeration *>(Scope), CTy);
+ break;
+ // FIXME: Not implemented.
+ case dwarf::DW_TAG_variant_part:
+ case dwarf::DW_TAG_namelist:
+ break;
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_class_type: {
+ constructAggregate(static_cast<LVScopeAggregate *>(Scope), CTy);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (Tag == dwarf::DW_TAG_enumeration_type ||
+ Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
+ Tag == dwarf::DW_TAG_union_type) {
+ // Add accessibility info if available.
+ addAccess(Scope, CTy->getFlags());
+
+ // Add source line info if available.
+ if (!CTy->isForwardDecl())
+ addSourceLine(Scope, CTy);
+ }
+}
+
+// DIDerivedType
+// DW_TAG_atomic_type
+// DW_TAG_const_type
+// DW_TAG_friend
+// DW_TAG_inheritance
+// DW_TAG_member
+// DW_TAG_immutable_type
+// DW_TAG_pointer_type
+// DW_TAG_ptr_to_member_type
+// DW_TAG_reference_type
+// DW_TAG_restrict_type
+// DW_TAG_typedef
+// DW_TAG_volatile_type
+void LVIRReader::constructType(LVElement *Element, const DIDerivedType *DT) {
+ assert(Element && "Invalid logical element");
+ assert(DT && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructType] DIDerivedType\n";
+ DT->dump();
+ });
+
+ // For DW_TAG_member, the flag is set during the construction of the
+ // aggregate type (DICompositeType).
+ if (DT->getTag() != dwarf::DW_TAG_member)
+ Element->setIsFinalized();
+
+ LVElement *BaseType = getOrCreateType(DT->getBaseType());
+ Element->setType(BaseType);
+
+ // Add accessibility info if available.
+ if (!DT->isStaticMember())
+ addAccess(Element, DT->getFlags());
+
+ if (DT->isVirtual())
+ Element->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual);
+
+ if (DT->isArtificial())
+ Element->setIsArtificial();
+
+ // Add source line info if available and TyDesc is not a forward declaration.
+ if (!DT->isForwardDecl())
+ addSourceLine(Element, DT);
+}
+
+// DISubroutineType
+void LVIRReader::constructType(LVScope *Function,
+ const DISubroutineType *SPTy) {
+ assert(Function && "Invalid logical element");
+ assert(SPTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructType] DISubroutineType\n";
+ SPTy->dump();
+ });
+
+ if (Function->getIsFinalized())
+ return;
+ Function->setIsFinalized();
+
+ // For DISubprogram, the DISubroutineType contains the types for:
+ // return type, param 1 type, ..., param n type
+ DITypeRefArray Args = SPTy->getTypeArray();
+ if (Args.size()) {
+ LVElement *ElementType = getOrCreateType(Args[0]);
+ Function->setType(ElementType);
+ }
+
+ constructSubprogramArguments(Function, Args);
+}
+
+// DINamespace
+LVScope *LVIRReader::getOrCreateNamespace(const DINamespace *NS) {
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateNamespace] DINamespace\n";
+ NS->dump();
+ });
+
+ LVScope *Scope = getOrCreateScope(NS);
+ if (Scope) {
+ StringRef Name = NS->getName();
+ if (Name.empty())
+ Scope->setName("(anonymous namespace)");
+ }
+
+ return Scope;
+}
+
+LVScope *LVIRReader::getOrCreateScope(const DIScope *Context) {
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateScope] DIScope\n";
+ Context->dump();
+ });
+
+ // Check if the scope is already created.
+ LVScope *Scope = getScopeForSeenMD(Context);
+ if (Scope)
+ return Scope;
+
+ Scope = static_cast<LVScope *>(constructElement(Context));
+ if (Scope) {
+ // Add element to parent.
+ LVScope *Parent = getParentScope(Context);
+ Parent->addElement(Scope);
+ }
+
+ return Scope;
+}
+
+// DICompositeType
+// DIDerivedType
+// DISubroutineType
+LVElement *LVIRReader::getOrCreateType(const DIType *Ty, LVScope *Scope) {
+ if (!Ty)
+ return nullptr;
+
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateType] DIType\n";
+ Ty->dump();
+ });
+
+ // Check if the element is already created.
+ LVElement *Element = getElementForSeenMD(Ty);
+ if (Element)
+ return Element;
+
+ Element = constructElement(Ty);
+ if (Element) {
+ // Add element to parent.
+ LVScope *Parent = Scope ? Scope : getParentScope(Ty);
+ Parent->addElement(Element);
+
+ if (/*const DIBasicType *BT =*/dyn_cast<DIBasicType>(Ty)) {
+ Element->setIsFinalized();
+ } else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Ty)) {
+ constructType(Element, DT);
+ } else if (const DICompositeType *CTy = dyn_cast<DICompositeType>(Ty)) {
+ constructType(static_cast<LVScope *>(Element), CTy);
+ } else if (const DISubroutineType *SPTy = dyn_cast<DISubroutineType>(Ty)) {
+ constructType(static_cast<LVScope *>(Element), SPTy);
+ }
+ }
+
+ return Element;
+}
+
+// DIGlobalVariableExpression
+LVSymbol *
+LVIRReader::getOrCreateVariable(const DIGlobalVariableExpression *GVE) {
+ assert(GVE && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateVariable] DIGlobalVariableExpression\n";
+ GVE->dump();
+ });
+
+ const DIGlobalVariable *DIGV = GVE->getVariable();
+ LVSymbol *Symbol = getSymbolForSeenMD(DIGV);
+ if (!Symbol)
+ Symbol = getOrCreateVariable(DIGV);
+
+ if (Symbol) {
+ // Add location and operation entries.
+ Symbol->addLocation(dwarf::DW_AT_location, /*LowPC=*/0, /*HighPC=*/-1,
+ /*SectionOffset=*/0, /*OffsetOnEntry=*/0);
+ Symbol->addLocationOperands(dwarf::DW_OP_addrx, PoolAddressIndex++);
+ if (const DIExpression *DIExpr = GVE->getExpression())
+ addConstantValue(Symbol, DIExpr);
+ }
+ return Symbol;
+}
+
+LVSymbol *LVIRReader::getOrCreateInlinedVariable(LVSymbol *OriginSymbol,
+ const DILocation *DL) {
+ assert(OriginSymbol && "Invalid logical element");
+ assert(DL && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateInlinedVariable] DIVariable\n";
+ DL->dump();
+ });
+
+ const DILocation *InlinedAt = DL->getInlinedAt();
+ if (!InlinedAt) {
+ return nullptr;
+ }
+
+ dwarf::Tag Tag = OriginSymbol->getTag();
+ LVSymbol *InlinedSymbol = static_cast<LVSymbol *>(createElement(Tag));
+ if (InlinedSymbol) {
+ InlinedSymbol->setTag(Tag);
+ InlinedSymbol->setIsFinalized();
+ InlinedSymbol->setName(OriginSymbol->getName());
+ InlinedSymbol->setType(OriginSymbol->getType());
+
+ InlinedSymbol->setCallLineNumber(InlinedAt->getLine());
+ InlinedSymbol->setCallFilenameIndex(
+ getOrCreateSourceID(InlinedAt->getFile()));
+
+ OriginSymbol->setInlineCode(dwarf::DW_INL_inlined);
+ InlinedSymbol->setReference(OriginSymbol);
+ InlinedSymbol->setHasReferenceAbstract();
+
+ if (OriginSymbol->getIsParameter())
+ InlinedSymbol->setIsParameter();
+
+ LVScope *AbstractScope = OriginSymbol->getParentScope();
+ assert(AbstractScope && "Invalid logical element");
+ LVScope *InlinedScope = getInlinedScope(AbstractScope, InlinedAt);
+ if (!InlinedScope)
+ InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
+
+ assert(InlinedScope && "Parent scope is NULL.");
+ InlinedScope->addElement(InlinedSymbol);
+ }
+
+ return InlinedSymbol;
+}
+
+// DIGlobalVariable
+// DILocalVariable
+LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
+ const DILocation *DL) {
+ assert(Var && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateVariable] DIVariable\n";
+ Var->dump();
+ if (DL) {
+ dbgs() << "DILocation\n";
+ DL->dump();
+ }
+ });
+
+ // Use the 'InlinedAt' information to identify a symbol that is being
+ // inlined. Its abstract representation is created just once.
+ const DILocation *InlinedAt = DL ? DL->getInlinedAt() : nullptr;
+
+ LVSymbol *Symbol = getSymbolForSeenMD(Var);
+ if (Symbol && Symbol->getIsFinalized() && !InlinedAt)
+ return Symbol;
+
+ if (!options().getPrintSymbols()) {
+ // Just create the symbol type.
+ getOrCreateType(Var->getType());
+ if (const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var)) {
+ if (MDTuple *TP = GV->getTemplateParams())
+ addTemplateParams(Symbol, DINodeArray(TP));
+ }
+ return nullptr;
+ }
+
+ if (!Symbol)
+ Symbol = static_cast<LVSymbol *>(constructElement(Var));
+ if (Symbol && !Symbol->getIsFinalized()) {
+ Symbol->setIsFinalized();
+ LVScope *Parent = getParentScope(Var);
+ Parent->addElement(Symbol);
+
+ Symbol->setName(Var->getName());
+
+ // Create symbol type.
+ if (LVElement *SymbolType = getOrCreateType(Var->getType()))
+ Symbol->setType(SymbolType);
+
+ if (const DILocalVariable *LV = dyn_cast<DILocalVariable>(Var)) {
+ // Add line number info.
+ addSourceLine(Symbol, LV);
+ if (LV->isParameter()) {
+ Symbol->setIsParameter();
+ if (LV->isArtificial())
+ Symbol->setIsArtificial();
+ }
+ } else {
+ const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var);
+ if (useAllLinkageNames())
+ Symbol->setLinkageName(GV->getLinkageName());
+
+ // Get 'declaration' node in order to generate the DW_AT_specification.
+ if (const DIDerivedType *GVDecl = GV->getStaticDataMemberDeclaration()) {
+ LVSymbol *Reference = static_cast<LVSymbol *>(getOrCreateType(GVDecl));
+ if (Reference) {
+ Symbol->setReference(Reference);
+ Symbol->setHasReferenceSpecification();
+ }
+ } else {
+ if (!GV->isLocalToUnit())
+ Symbol->setIsExternal();
+ // Add line number info.
+ addSourceLine(Symbol, GV);
+ }
+
+ if (MDTuple *TP = GV->getTemplateParams())
+ addTemplateParams(Symbol, DINodeArray(TP));
+ }
+ }
+
+ // Create the 'inlined' symbol.
+ if (DL)
+ getOrCreateInlinedVariable(Symbol, DL);
+
+ return Symbol;
+}
+
+#ifdef LLVM_DEBUG
+void LVIRReader::printAllInstructions(BasicBlock *BB) {
+ LLVM_DEBUG({
+ dbgs() << "\nBegin all instructions:\n";
+ for (Instruction &I : *BB) {
+ dbgs() << "Instruction: '" << I << "'\n";
+ for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
+ DVR.getVariable()->dump();
+ }
+ dbgs() << "End all instructions:\n\n";
+ });
+}
+#endif
+
+void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[processBasicBlocks] DISubprogram\n";
+ SP->dump();
+ });
+
+ // Check if we need to add a dwarf::DW_TAG_unspecified_parameters.
+ bool AddUnspecifiedParameters = false;
+ if (const DISubroutineType *SPTy = SP->getType()) {
+ DITypeRefArray Args = SPTy->getTypeArray();
+ unsigned N = Args.size();
+ if (N > 1) {
+ const DIType *Ty = Args[N - 1];
+ if (!Ty)
+ AddUnspecifiedParameters = true;
+ }
+ }
+
+ LVScope *Scope = getOrCreateSubprogram(SP);
+
+ SmallVector<DebugVariableAggregate> SeenVars;
+
+ // Handle dbg.values and dbg.declare.
+ auto HandleDbgVariable = [&](auto *DbgVar) {
+ LLVM_DEBUG({
+ dbgs() << "\n[HandleDbgVariable]\n";
+ DbgVar->dump();
+ });
+
+ DebugVariableAggregate DVA(DbgVar);
+ if (!DbgValueRanges->hasVariableEntry(DVA)) {
+ DbgValueRanges->addVariable(&F, DVA);
+ SeenVars.push_back(DVA);
+ }
+
+ // Skip undefined values.
+ if (!DbgVar->isKillLocation())
+ getOrCreateVariable(DbgVar->getVariable(), DbgVar->getDebugLoc().get());
+ };
+
+ // Generate logical debug line before prologue.
+ bool GenerateLineBeforePrologue = true;
+ for (BasicBlock &BB : F) {
+ printAllInstructions(&BB);
+
+ for (Instruction &I : BB) {
+ LLVM_DEBUG(dbgs() << "\nInstruction: '" << I << "'\n");
+
+ for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
+ HandleDbgVariable(&DVR);
+
+ if (const auto *DL =
+ cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg)))
+ getOrCreateAbstractScope(Scope, DL);
+
+ if (options().getPrintAnyLine())
+ constructLine(Scope, SP, I, GenerateLineBeforePrologue);
+
+ InstrLineAddrMap[I.getIterator().getNodePtr()] = CurrentOffset;
+
+ // Update code offset.
+ updateLineOffset();
+ }
+ InstrLineAddrMap[BB.end().getNodePtr()] = CurrentOffset;
+ }
+ GenerateLineBeforePrologue = false;
+
+ if (AddUnspecifiedParameters) {
+ LVElement *Parameter = createElement(dwarf::DW_TAG_unspecified_parameters);
+ if (Parameter) {
+ Parameter->setIsFinalized();
+ Scope->addElement(Parameter);
+ }
+ }
+
+ LLVM_DEBUG({ dbgs() << "Traverse seen debug variables\n"; });
+ for (auto DVA : SeenVars) {
+ LLVM_DEBUG({ DbgValueRanges->printValues(DVA, dbgs()); });
+ DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable());
+ LVSymbol *Symbol = getSymbolForSeenMD(LV);
+ // Undefined only value, ignore.
+ if (!Symbol)
+ continue;
+
+ DIType *Ty = LV->getType();
+ uint64_t Size = Ty ? Ty->getSizeInBits() / CHAR_BIT : 1;
+ LLVM_DEBUG({
+ LV->dump();
+ Ty->dump();
+ dbgs() << "Type size: " << Size << "\n";
+ });
+
+ auto AddLocationOp = [&](Value *V, bool IsMem) {
+ uint64_t RegValue = ValueNameMap.addValue(V);
+ if (IsMem)
+ Symbol->addLocationOperands(dwarf::DW_OP_bregx, {RegValue, 0});
+ else
+ Symbol->addLocationOperands(dwarf::DW_OP_regx, RegValue);
+ };
+
+ auto AddLocation = [&](DbgValueDef DV) {
+ bool IsMem = DV.IsMemory;
+ DIExpression *CanonicalExpr = const_cast<DIExpression *>(
+ DIExpression::convertToVariadicExpression(DV.Expression));
+ RawLocationWrapper Locations(DV.Locations);
+ for (DIExpression::ExprOperand ExprOp : CanonicalExpr->expr_ops()) {
+ if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg) {
+ AddLocationOp(Locations.getVariableLocationOp(ExprOp.getArg(0)),
+ IsMem);
+ } else {
+ if (ExprOp.getOp() > std::numeric_limits<uint8_t>::max())
+ LLVM_DEBUG(dbgs() << "Bad DWARF op: " << ExprOp.getOp() << "\n");
+ uint8_t ShortOp = (uint8_t)ExprOp.getOp();
+ Symbol->addLocationOperands(
+ ShortOp,
+ ArrayRef<uint64_t>(std::next(ExprOp.get()), ExprOp.getNumArgs()));
+ }
+ }
+ };
+
+ if (DbgValueRanges->hasSingleLocEntry(DVA)) {
+ DbgValueDef DV = DbgValueRanges->getSingleLoc(DVA);
+ Symbol->addLocation(llvm::dwarf::DW_AT_location, /*LowPC=*/0,
+ /*HighPC=*/-1, /*SectionOffset=*/0,
+ /*OffsetOnEntry=*/0);
+ assert(DV.IsMemory && "Single location should be memory!");
+ AddLocation(DV);
+ } else {
+ for (DbgRangeEntry Entry : DbgValueRanges->getVariableRanges(DVA)) {
+ // These line addresses should have already been inserted into the
+ // InstrLineAddrMap, so we assume they are present here.
+ LVOffset Start = InstrLineAddrMap.at(Entry.Start.getNodePtr());
+ LVOffset End = InstrLineAddrMap.at(Entry.End.getNodePtr());
+ Symbol->addLocation(llvm::dwarf::DW_AT_location, Start, End,
+ /*SectionOffset=*/0, /*OffsetOnEntry=*/0);
+ DbgValueDef DV = Entry.Value;
+ AddLocation(DV);
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// IR Reader entry point.
+//===----------------------------------------------------------------------===//
+Error LVIRReader::createScopes() {
+ LLVM_DEBUG({
+ W.startLine() << "\n";
+ W.printString("File", getFilename());
+ W.printString("Format", FileFormatName);
+ });
+
+ // The IR Reader supports only debug records.
+ // We identify the debug input format and if it is intrinsics, it is
+ // converted to the debug records.
+ if (Error Err = LVReader::createScopes())
+ return Err;
+
+ LLVMContext Context;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M = parseIR(
+ BitCodeIR ? BitCodeIR->getMemoryBufferRef() : *TextualIR, Err, Context);
+ if (!M)
+ return createStringError(errc::invalid_argument,
+ "Could not create IR information: %s",
+ getFilename().str().c_str());
+
+ if (!M->getNamedMetadata("llvm.dbg.cu")) {
+ LLVM_DEBUG(dbgs() << "Skipping module without debug info\n");
+ return Error::success();
+ }
+
+ DwarfVersion = M->getDwarfVersion();
+
+ LLVM_DEBUG({ dbgs() << "\nProcess CompileUnits\n"; });
+ for (const DICompileUnit *CU : M->debug_compile_units()) {
+ LLVM_DEBUG({
+ dbgs() << "\nDICompileUnit:\n";
+ CU->dump();
+ });
+
+ // Record if the current source language is Fortran.
+ mapFortranLanguage(CU->getSourceLanguage());
+
+ CompileUnit = static_cast<LVScopeCompileUnit *>(constructElement(CU));
+ CUNode = const_cast<DICompileUnit *>(CU);
+
+ const DIFile *File = CU->getFile();
+ CompileUnit->setName(File->getFilename());
+ CompileUnit->setCompilationDirectory(File->getDirectory());
+ CompileUnit->setIsFinalized();
+
+ Root->addElement(CompileUnit);
+
+ if (options().getAttributeProducer())
+ CompileUnit->setProducer(CU->getProducer());
----------------
CarlosAlbertoEnciso wrote:
Good point. Using the new feature `LVSourceLanguage`
```
uint16_t LanguageName = CU->getSourceLanguage().getUnversionedName();
LVSourceLanguage SL =
TheModule->getCodeViewFlag()
? LVSourceLanguage(
static_cast<llvm::codeview::SourceLanguage>(LanguageName))
: LVSourceLanguage(
static_cast<llvm::dwarf::SourceLanguage>(LanguageName));
setDefaultLowerBound(&SL);
if (options().getAttributeLanguage())
CompileUnit->setSourceLanguage(SL);
```
https://github.com/llvm/llvm-project/pull/135440
More information about the llvm-commits
mailing list