[llvm-branch-commits] [llvm] [llvm-debuginfo-analyzer] Add support for LLVM IR format. (PR #135440)
Jeremy Morse via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu May 1 07:59:01 PDT 2025
================
@@ -0,0 +1,2348 @@
+//===-- 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"
+
+// Extra debug traces. Default is false
+#define DEBUG_ALL
+
+// These flavours of DINodes are not handled:
+// DW_TAG_APPLE_property = 19896
+// DW_TAG_atomic_type = 71
+// DW_TAG_common_block = 26
+// DW_TAG_file_type = 41
+// DW_TAG_friend = 42
+// DW_TAG_generic_subrange = 69
+// DW_TAG_immutable_type = 75
+// DW_TAG_module = 30
+
+// 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;
+ }
+}
+
+// Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+// difference is setting the 'DICompileUnit::splitDebugFilename' to the
+// name of the split filename: "xxx.dwo".
+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.
+// In DWARF v4, the files are 1-indexed.
+// In DWARF v5, the files are 0-indexed.
+// 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;
+
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateSourceID] DIFile\n";
+ File->dump();
+ });
+#endif
+
+ 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.cend()) {
+ 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();
+ std::stringstream Stream;
+ if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
----------------
jmorse wrote:
Don't we need to check for whether the std::optional is empty before examining `Constant`? If it's guaranteed, best to assert that `Constant` isn't empty.
https://github.com/llvm/llvm-project/pull/135440
More information about the llvm-branch-commits
mailing list