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);
llvm::StringRef NameOfWrappedPass = "",
DebugInfoPerPass *DebugInfoBeforePass = nullptr);
-struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
+class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
+ 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);
};
DebugInfoPerPass *DebugInfoBeforePass = nullptr,
llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
-struct NewPMCheckDebugifyPass
+class NewPMCheckDebugifyPass
: public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
+ 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
}
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();
}
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();
}
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<const Function *>(IR))
- applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR)));
+ applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR)),
+ Mode, DebugInfoBeforePass, P);
else if (any_isa<const Module *>(IR))
- applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR)));
+ applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR)),
+ Mode, DebugInfoBeforePass, P);
});
PIC.registerAfterPassCallback([this](StringRef P, Any IR,
const PreservedAnalyses &PassPA) {
auto &F = *const_cast<Function *>(any_cast<const Function *>(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<const Module *>(IR)) {
auto &M = *const_cast<Module *>(any_cast<const Module *>(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);
}
});
}
-; 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
--- /dev/null
+; 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)
-; 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
DebugifyExport("debugify-export",
cl::desc("Export per-pass debugify statistics to this file"),
cl::value_desc("filename"));
+
+cl::opt<bool> VerifyEachDebugInfoPreserve(
+ "verify-each-debuginfo-preserve",
+ cl::desc("Start each pass with collecting and end it with checking of "
+ "debug info preservation."));
+
+cl::opt<std::string>
+ 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 };
bool ShouldPreserveAssemblyUseListOrder,
bool ShouldPreserveBitcodeUseListOrder,
bool EmitSummaryIndex, bool EmitModuleHash,
- bool EnableDebugify) {
+ bool EnableDebugify, bool VerifyDIPreserve) {
bool VerifyEachPass = VK == VK_VerifyEachPass;
Optional<PGOOptions> P;
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
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()) {
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) {
OptRemarkFile->keep();
if (DebugifyEach && !DebugifyExport.empty())
- exportDebugifyStats(DebugifyExport, Debugify.StatsMap);
+ exportDebugifyStats(DebugifyExport, Debugify.getDebugifyStatsMap());
return true;
}
extern cl::opt<bool> DebugifyEach;
extern cl::opt<std::string> DebugifyExport;
+extern cl::opt<bool> VerifyEachDebugInfoPreserve;
+extern cl::opt<std::string> VerifyDIPreserveExport;
+
namespace opt_tool {
enum OutputKind {
OK_NoOutput,
bool ShouldPreserveAssemblyUseListOrder,
bool ShouldPreserveBitcodeUseListOrder,
bool EmitSummaryIndex, bool EmitModuleHash,
- bool EnableDebugify);
+ bool EnableDebugify, bool VerifyDIPreserve);
} // namespace llvm
#endif
cl::desc("Start the pipeline with collecting and end it with checking of "
"debug info preservation."));
-static cl::opt<bool> VerifyEachDebugInfoPreserve(
- "verify-each-debuginfo-preserve",
- cl::desc("Start each pass with collecting and end it with checking of "
- "debug info preservation."));
-
-static cl::opt<std::string>
- 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<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
ThinLinkOut.get(), RemarksFile.get(), Pipeline,
Passes, PluginList, OK, VK, PreserveAssemblyUseListOrder,
PreserveBitcodeUseListOrder, EmitSummaryIndex,
- EmitModuleHash, EnableDebugify)
+ EmitModuleHash, EnableDebugify,
+ VerifyDebugInfoPreserve)
? 0
: 1;
}