[PATCH v2 18/50] helper-to-tcg: PrepareForOptPass, collect debuginfo
Anton Johansson via qemu development <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
Debug information is collected before any non-preserving optimization pass is ran. Currently, only variable definitions are parsed, mapping a Value * to a name and typename. Signed-off-by: Anton Johansson <[email protected]> --- .../helper-to-tcg/include/DebugInfo.hpp | 46 ++++++++++++++++ .../include/PrepareForOptPass.hpp | 10 ++-- subprojects/helper-to-tcg/src/Pipeline.cpp | 3 +- .../PrepareForOptPass/PrepareForOptPass.cpp | 52 +++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 subprojects/helper-to-tcg/include/DebugInfo.hpp diff --git a/subprojects/helper-to-tcg/include/DebugInfo.hpp b/subprojects/helper-to-tcg/include/DebugInfo.hpp new file mode 100644 index 0000000000..27e545c6b7 --- /dev/null +++ b/subprojects/helper-to-tcg/include/DebugInfo.hpp @@ -0,0 +1,46 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see <http://www.gnu.org/licenses/>. +// + +#pragma once + +#include <llvm/ADT/StringRef.h> +#include <llvm/IR/ValueMap.h> + +namespace llvm { +class Value; +} + +// StringRefs will refer do debug metadata fields which have the same +// lifetime as the LLVMContext and survive accross optimizations and +// possible deletions of functions/variables. +struct DebugInfo { + llvm::StringRef VarName; + llvm::StringRef BaseTypeName; +}; + +using DebugInfoMapTy = llvm::ValueMap<const llvm::Value *, DebugInfo>; + +// Helper to get the variable name from debug info associated with a particular +// value, or default construct an empty name. +inline llvm::StringRef getDebugVarName(const DebugInfoMapTy &DM, + const llvm::Value *V) { + auto It = DM.find(V); + if (It != DM.end()) { + return It->second.VarName; + } + return {}; +} diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp index 08ca9a43bb..43cf77190a 100644 --- a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp @@ -17,6 +17,7 @@ #pragma once +#include "DebugInfo.hpp" #include "FunctionAnnotation.hpp" #include <llvm/IR/PassManager.h> @@ -29,10 +30,13 @@ class PrepareForOptPass : public llvm::PassInfoMixin<PrepareForOptPass> { AnnotationMapTy &ResultAnnotations; + DebugInfoMapTy &ResultDebugInfo; - public: - PrepareForOptPass(AnnotationMapTy &ResultAnnotations) - : ResultAnnotations(ResultAnnotations) {} +public: + PrepareForOptPass(AnnotationMapTy &ResultAnnotations, + DebugInfoMapTy &ResultDebugInfo) + : ResultAnnotations(ResultAnnotations), + ResultDebugInfo(ResultDebugInfo) {} llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helper-to-tcg/src/Pipeline.cpp index 89637eaec6..a11c5fd353 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -193,7 +193,8 @@ int main(int argc, char **argv) { // but is correlct in LLVM-terms. AnnotationMapTy Annotations; - MPM.addPass(PrepareForOptPass(Annotations)); + DebugInfoMapTy DebugInfo; + MPM.addPass(PrepareForOptPass(Annotations, DebugInfo)); { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp index a7bee53582..7a9b954d7c 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -26,6 +26,9 @@ #include <llvm/ADT/StringSet.h> #include <llvm/Demangle/Demangle.h> #include <llvm/IR/Constants.h> +#if LLVM_VERSION_MAJOR >= 19 +#include <llvm/IR/DebugProgramInstruction.h> +#endif #include <llvm/IR/Function.h> #include <llvm/IR/Instruction.h> #include <llvm/IR/Instructions.h> @@ -288,6 +291,53 @@ static void replaceRetaddrWithUndef(Module &M) { } } +static void collectDebugInfo(Function &F, DebugInfoMapTy &ResultDebugInfo) { + StringSet EncounteredNames; + for (auto &BB : F) { + for (Instruction &I : BB) { +#if LLVM_VERSION_MAJOR >= 19 + for (DbgVariableRecord &DVR : + filterDbgVars(I.getDbgRecordRange())) { + if (!DVR.isDbgValue()) { + continue; + } + StringRef BaseType{}; + StringRef VarName{}; + if (auto *Derived = + dyn_cast<DIDerivedType>(DVR.getVariable()->getType())) { + BaseType = Derived->getBaseType()->getName(); + } + VarName = DVR.getVariable()->getName(); + if (ResultDebugInfo.find(DVR.getValue(0)) == + ResultDebugInfo.end() and + !EncounteredNames.contains(VarName.data())) { + ResultDebugInfo[DVR.getValue(0)] = {VarName, BaseType}; + EncounteredNames.insert(VarName.data()); + } + } +#else + if (I.isDebugOrPseudoInst()) { + if (const auto *Dbg = dyn_cast<DbgValueInst>(&I)) { + StringRef BaseType{}; + StringRef VarName{}; + if (auto *Derived = dyn_cast<DIDerivedType>( + Dbg->getVariable()->getType())) { + BaseType = Derived->getBaseType()->getName(); + } + VarName = Dbg->getVariable()->getName(); + if (ResultDebugInfo.find(Dbg->getValue(0)) == + ResultDebugInfo.end() and + !EncounteredNames.contains(VarName.data())) { + ResultDebugInfo[Dbg->getValue(0)] = {VarName, BaseType}; + EncounteredNames.insert(VarName.data()); + } + } + } +#endif + } + } +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { demangleFunctionNames(M); @@ -305,6 +355,8 @@ PreservedAnalyses PrepareForOptPass::run(Module &M, if (F.getReturnType()->isStructTy()) { F.addFnAttr(Attribute::AttrKind::AlwaysInline); } + // Populate variable and type names for `Value`s from debug info. + collectDebugInfo(F, ResultDebugInfo); } return PreservedAnalyses::none(); -- 2.52.0