diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -788,6 +788,18 @@ SI.registerCallbacks(PIC, &FAM); PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC); + // Enable verify-debuginfo-preserve-each for new PM. + DebugifyEachInstrumentation Debugify; + DebugInfoPerPass DebugInfoBeforePass; + if (CodeGenOpts.EnableDIPreservationVerify) { + Debugify.setDebugifyMode(DebugifyMode::OriginalDebugInfo); + Debugify.setDebugInfoBeforePass(DebugInfoBeforePass); + + if (!CodeGenOpts.DIBugsReportFilePath.empty()) + Debugify.setOrigDIVerifyBugsReportFilePath( + CodeGenOpts.DIBugsReportFilePath); + Debugify.registerCallbacks(PIC); + } // Attempt to load pass plugins and register their callbacks with PB. for (auto &PluginFN : CodeGenOpts.PassPlugins) { auto PassPlugin = PassPlugin::Load(PluginFN); diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h --- a/llvm/include/llvm/Transforms/Utils/Debugify.h +++ b/llvm/include/llvm/Transforms/Utils/Debugify.h @@ -101,7 +101,18 @@ llvm::StringRef NameOfWrappedPass = "", DebugInfoPerPass *DebugInfoBeforePass = nullptr); -struct NewPMDebugifyPass : public llvm::PassInfoMixin { +class NewPMDebugifyPass : public llvm::PassInfoMixin { + llvm::StringRef NameOfWrappedPass; + DebugInfoPerPass *DebugInfoBeforePass = nullptr; + enum DebugifyMode Mode = DebugifyMode::NoDebugify; +public: + NewPMDebugifyPass( + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + llvm::StringRef NameOfWrappedPass = "", + DebugInfoPerPass *DebugInfoBeforePass = nullptr) + : NameOfWrappedPass(NameOfWrappedPass), + DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {} + llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); }; @@ -148,18 +159,65 @@ DebugInfoPerPass *DebugInfoBeforePass = nullptr, llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); -struct NewPMCheckDebugifyPass +class NewPMCheckDebugifyPass : public llvm::PassInfoMixin { + llvm::StringRef NameOfWrappedPass; + llvm::StringRef OrigDIVerifyBugsReportFilePath; + DebugifyStatsMap *StatsMap; + DebugInfoPerPass *DebugInfoBeforePass; + enum DebugifyMode Mode; + bool Strip; +public: + NewPMCheckDebugifyPass( + bool Strip = false, llvm::StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + DebugInfoPerPass *DebugInfoBeforePass = nullptr, + llvm::StringRef OrigDIVerifyBugsReportFilePath = "") + : NameOfWrappedPass(NameOfWrappedPass), + OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), + StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode), + Strip(Strip) {} + llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); }; namespace llvm { void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map); -struct DebugifyEachInstrumentation { - DebugifyStatsMap StatsMap; +class DebugifyEachInstrumentation { + llvm::StringRef OrigDIVerifyBugsReportFilePath = ""; + DebugInfoPerPass *DebugInfoBeforePass = nullptr; + enum DebugifyMode Mode = DebugifyMode::NoDebugify; + DebugifyStatsMap *DIStatsMap = nullptr; + +public: void registerCallbacks(PassInstrumentationCallbacks &PIC); + // Used within DebugifyMode::SyntheticDebugInfo mode. + void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } + const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } + // Used within DebugifyMode::OriginalDebugInfo mode. + void setDebugInfoBeforePass(DebugInfoPerPass &PerPassMap) { + DebugInfoBeforePass = &PerPassMap; + } + DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } + + void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { + OrigDIVerifyBugsReportFilePath = BugsReportFilePath; + } + StringRef getOrigDIVerifyBugsReportFilePath() const { + return OrigDIVerifyBugsReportFilePath; + } + + void setDebugifyMode(enum DebugifyMode M) { Mode = M; } + + bool isSyntheticDebugInfo() const { + return Mode == DebugifyMode::SyntheticDebugInfo; + } + bool isOriginalDebugInfoMode() const { + return Mode == DebugifyMode::OriginalDebugInfo; + } }; /// DebugifyCustomPassManager wraps each pass with the debugify passes if diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -961,8 +961,13 @@ } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - applyDebugifyMetadata(M, M.functions(), - "ModuleDebugify: ", /*ApplyToMF*/ nullptr); + if (Mode == DebugifyMode::SyntheticDebugInfo) + applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); + else + collectDebugInfoMetadata(M, M.functions(), *DebugInfoBeforePass, + "ModuleDebugify (original debuginfo)", + NameOfWrappedPass); return PreservedAnalyses::all(); } @@ -992,8 +997,14 @@ PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, - nullptr); + if (Mode == DebugifyMode::SyntheticDebugInfo) + checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, + "CheckModuleDebugify", Strip, StatsMap); + else + checkDebugInfoMetadata( + M, M.functions(), *DebugInfoBeforePass, + "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass, + OrigDIVerifyBugsReportFilePath); return PreservedAnalyses::all(); } @@ -1006,13 +1017,15 @@ void DebugifyEachInstrumentation::registerCallbacks( PassInstrumentationCallbacks &PIC) { - PIC.registerBeforeNonSkippedPassCallback([](StringRef P, Any IR) { + PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) { if (isIgnoredPass(P)) return; if (any_isa(IR)) - applyDebugify(*const_cast(any_cast(IR))); + applyDebugify(*const_cast(any_cast(IR)), + Mode, DebugInfoBeforePass, P); else if (any_isa(IR)) - applyDebugify(*const_cast(any_cast(IR))); + applyDebugify(*const_cast(any_cast(IR)), + Mode, DebugInfoBeforePass, P); }); PIC.registerAfterPassCallback([this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { @@ -1022,12 +1035,24 @@ auto &F = *const_cast(any_cast(IR)); Module &M = *F.getParent(); auto It = F.getIterator(); - checkDebugifyMetadata(M, make_range(It, std::next(It)), P, - "CheckFunctionDebugify", /*Strip=*/true, &StatsMap); + if (Mode == DebugifyMode::SyntheticDebugInfo) + checkDebugifyMetadata(M, make_range(It, std::next(It)), P, + "CheckFunctionDebugify", /*Strip=*/true, DIStatsMap); + else + checkDebugInfoMetadata( + M, make_range(It, std::next(It)), *DebugInfoBeforePass, + "CheckModuleDebugify (original debuginfo)", + P, OrigDIVerifyBugsReportFilePath); } else if (any_isa(IR)) { auto &M = *const_cast(any_cast(IR)); - checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify", - /*Strip=*/true, &StatsMap); + if (Mode == DebugifyMode::SyntheticDebugInfo) + checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify", + /*Strip=*/true, DIStatsMap); + else + checkDebugInfoMetadata( + M, M.functions(), *DebugInfoBeforePass, + "CheckModuleDebugify (original debuginfo)", + P, OrigDIVerifyBugsReportFilePath); } }); } diff --git a/llvm/test/DebugInfo/debugify-original-no-dbg-info.ll b/llvm/test/DebugInfo/debugify-original-no-dbg-info.ll --- a/llvm/test/DebugInfo/debugify-original-no-dbg-info.ll +++ b/llvm/test/DebugInfo/debugify-original-no-dbg-info.ll @@ -1,4 +1,4 @@ -; RUN: opt -verify-debuginfo-preserve -instcombine --enable-new-pm=false -S -o - < %s 2>&1 | FileCheck %s +; RUN: opt -verify-debuginfo-preserve -instcombine -S -o - < %s 2>&1 | FileCheck %s ; CHECK: ModuleDebugify (original debuginfo): Skipping module without debug info ; CHECK-NEXT: CheckModuleDebugify (original debuginfo): Skipping module without debug info diff --git a/llvm/test/DebugInfo/verify-di-preserve.ll b/llvm/test/DebugInfo/verify-di-preserve.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/verify-di-preserve.ll @@ -0,0 +1,52 @@ +; RUN: opt %s -verify-debuginfo-preserve -instcombine -disable-output 2>&1 | FileCheck --check-prefix=VERIFY %s + +; VERIFY: CheckModuleDebugify (original debuginfo): + +; RUN: opt %s -verify-each-debuginfo-preserve -O2 -disable-output 2>&1 | FileCheck --check-prefix=VERIFY-EACH %s + +; VERIFY-EACH: DeadArgumentEliminationPass +; VERIFY-EACH: GlobalDCEPass + +; ModuleID = 'm.c' +source_filename = "m.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @foo(i32 %i) !dbg !8 { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !13, metadata !DIExpression()), !dbg !14 + %0 = load i32, i32* %i.addr, align 4, !dbg !15 + %call = call i32 @goo(i32 %0), !dbg !16 + ret i32 %call, !dbg !17 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +declare dso_local i32 @goo(i32) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "m.c", directory: "/dir") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 14.0.0"} +!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{} +!13 = !DILocalVariable(name: "i", arg: 1, scope: !8, file: !1, line: 2, type: !11) +!14 = !DILocation(line: 2, column: 13, scope: !8) +!15 = !DILocation(line: 3, column: 14, scope: !8) +!16 = !DILocation(line: 3, column: 10, scope: !8) +!17 = !DILocation(line: 3, column: 3, scope: !8) diff --git a/llvm/test/Transforms/Util/Debugify/loc-only-original-mode.ll b/llvm/test/Transforms/Util/Debugify/loc-only-original-mode.ll --- a/llvm/test/Transforms/Util/Debugify/loc-only-original-mode.ll +++ b/llvm/test/Transforms/Util/Debugify/loc-only-original-mode.ll @@ -1,16 +1,16 @@ -; RUN: opt < %s -deadargelim -enable-new-pm=false \ +; RUN: opt < %s -deadargelim \ ; RUN: -verify-each-debuginfo-preserve \ ; RUN: -debugify-level=locations -S 2>&1 | FileCheck %s -; RUN: opt < %s -deadargelim -enable-new-pm=false \ +; RUN: opt < %s -deadargelim \ ; RUN: -verify-each-debuginfo-preserve \ ; RUN: -debugify-level=location+variables -S 2>&1 | FileCheck %s --check-prefix=CHECK-DROP -; RUN: opt < %s -deadargelim -enable-new-pm=false \ +; RUN: opt < %s -deadargelim \ ; RUN: -verify-each-debuginfo-preserve \ ; RUN: -debugify-func-limit=0 -S 2>&1 | FileCheck %s -; RUN: opt < %s -deadargelim -enable-new-pm=false \ +; RUN: opt < %s -deadargelim \ ; RUN: -verify-each-debuginfo-preserve \ ; RUN: -debugify-func-limit=2 -S 2>&1 | FileCheck %s --check-prefix=CHECK-DROP diff --git a/llvm/tools/opt/NewPMDriver.h b/llvm/tools/opt/NewPMDriver.h --- a/llvm/tools/opt/NewPMDriver.h +++ b/llvm/tools/opt/NewPMDriver.h @@ -33,6 +33,9 @@ extern cl::opt DebugifyEach; extern cl::opt DebugifyExport; +extern cl::opt VerifyEachDebugInfoPreserve; +extern cl::opt VerifyDIPreserveExport; + namespace opt_tool { enum OutputKind { OK_NoOutput, @@ -74,7 +77,7 @@ bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash, - bool EnableDebugify); + bool EnableDebugify, bool VerifyDIPreserve); } // namespace llvm #endif diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -49,6 +49,19 @@ DebugifyExport("debugify-export", cl::desc("Export per-pass debugify statistics to this file"), cl::value_desc("filename")); + +cl::opt VerifyEachDebugInfoPreserve( + "verify-each-debuginfo-preserve", + cl::desc("Start each pass with collecting and end it with checking of " + "debug info preservation.")); + +cl::opt + VerifyDIPreserveExport("verify-di-preserve-export", + cl::desc("Export debug info preservation failures into " + "specified (JSON) file (should be abs path as we use" + " append mode to insert new JSON objects)"), + cl::value_desc("filename"), cl::init("")); + } // namespace llvm enum class DebugLogging { None, Normal, Verbose, Quiet }; @@ -280,7 +293,7 @@ bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash, - bool EnableDebugify) { + bool EnableDebugify, bool VerifyDIPreserve) { bool VerifyEachPass = VK == VK_VerifyEachPass; Optional P; @@ -337,8 +350,19 @@ PrintPassOpts); SI.registerCallbacks(PIC, &FAM); DebugifyEachInstrumentation Debugify; - if (DebugifyEach) + DebugifyStatsMap DIStatsMap; + DebugInfoPerPass DebugInfoBeforePass; + if (DebugifyEach) { + Debugify.setDIStatsMap(DIStatsMap); + Debugify.setDebugifyMode(DebugifyMode::SyntheticDebugInfo); + Debugify.registerCallbacks(PIC); + } else if (VerifyEachDebugInfoPreserve) { + Debugify.setDebugInfoBeforePass(DebugInfoBeforePass); + Debugify.setDebugifyMode(DebugifyMode::OriginalDebugInfo); + Debugify.setOrigDIVerifyBugsReportFilePath( + VerifyDIPreserveExport); Debugify.registerCallbacks(PIC); + } PipelineTuningOptions PTO; // LoopUnrolling defaults on to true and DisableLoopUnrolling is initialized @@ -417,6 +441,9 @@ MPM.addPass(VerifierPass()); if (EnableDebugify) MPM.addPass(NewPMDebugifyPass()); + if (VerifyDIPreserve) + MPM.addPass(NewPMDebugifyPass(DebugifyMode::OriginalDebugInfo, "", + &DebugInfoBeforePass)); // Add passes according to the -passes options. if (!PassPipeline.empty()) { @@ -456,7 +483,11 @@ if (VK > VK_NoVerifier) MPM.addPass(VerifierPass()); if (EnableDebugify) - MPM.addPass(NewPMCheckDebugifyPass()); + MPM.addPass(NewPMCheckDebugifyPass(false, "", &DIStatsMap)); + if (VerifyDIPreserve) + MPM.addPass(NewPMCheckDebugifyPass( + false, "", nullptr, DebugifyMode::OriginalDebugInfo, &DebugInfoBeforePass, + VerifyDIPreserveExport)); // Add any relevant output pass at the end of the pipeline. switch (OK) { @@ -504,7 +535,7 @@ OptRemarkFile->keep(); if (DebugifyEach && !DebugifyExport.empty()) - exportDebugifyStats(DebugifyExport, Debugify.StatsMap); + exportDebugifyStats(DebugifyExport, Debugify.getDebugifyStatsMap()); return true; } diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -206,18 +206,6 @@ cl::desc("Start the pipeline with collecting and end it with checking of " "debug info preservation.")); -static cl::opt VerifyEachDebugInfoPreserve( - "verify-each-debuginfo-preserve", - cl::desc("Start each pass with collecting and end it with checking of " - "debug info preservation.")); - -static cl::opt - VerifyDIPreserveExport("verify-di-preserve-export", - cl::desc("Export debug info preservation failures into " - "specified (JSON) file (should be abs path as we use" - " append mode to insert new JSON objects)"), - cl::value_desc("filename"), cl::init("")); - static cl::opt PrintBreakpoints("print-breakpoints-for-testing", cl::desc("Print select breakpoints location for testing")); @@ -823,7 +811,8 @@ ThinLinkOut.get(), RemarksFile.get(), Pipeline, Passes, PluginList, OK, VK, PreserveAssemblyUseListOrder, PreserveBitcodeUseListOrder, EmitSummaryIndex, - EmitModuleHash, EnableDebugify) + EmitModuleHash, EnableDebugify, + VerifyDebugInfoPreserve) ? 0 : 1; }