mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-12 17:16:09 +00:00

Before we start addressing the issue with having a lot of false positives when using debugify in the original mode, we have made a few patches that should speed up the execution of the testing utility Passes. For example, when testing a large project (let's say LLVM project itself), we can face a lot of potential DI issues. Usually, we use -verify-each-debuginfo-preserve (that is very similar to -debugify-each) -- it collects DI metadata before each Pass, and after the Pass it checks if the Pass preserved the DI metadata. However, we can speed up this process, since we don't need to collect DI metadata before each Pass -- we could use the DI metadata that are collected after the previous Pass from the pipeline as an input for the next Pass. This patch speeds up the utility for ~2x. Differential Revision: https://reviews.llvm.org/D115622
265 lines
9.8 KiB
C++
265 lines
9.8 KiB
C++
//===- DebugifyTest.cpp - Debugify unit tests -----------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Transforms/Utils/Debugify.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
|
SMDiagnostic Err;
|
|
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
|
|
if (!Mod)
|
|
Err.print("DebugifyTest", errs());
|
|
return Mod;
|
|
}
|
|
|
|
namespace llvm {
|
|
void initializeDebugInfoDropPass(PassRegistry &);
|
|
void initializeDebugInfoDummyAnalysisPass(PassRegistry &);
|
|
|
|
namespace {
|
|
struct DebugInfoDrop : public FunctionPass {
|
|
static char ID;
|
|
bool runOnFunction(Function &F) override {
|
|
// Drop DISubprogram.
|
|
F.setSubprogram(nullptr);
|
|
for (BasicBlock &BB : F) {
|
|
// Remove debug locations.
|
|
for (Instruction &I : BB)
|
|
I.setDebugLoc(DebugLoc());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
}
|
|
|
|
DebugInfoDrop() : FunctionPass(ID) {}
|
|
};
|
|
|
|
struct DebugValueDrop : public FunctionPass {
|
|
static char ID;
|
|
bool runOnFunction(Function &F) override {
|
|
SmallVector<DbgVariableIntrinsic *, 4> Dbgs;
|
|
for (BasicBlock &BB : F) {
|
|
// Remove dbg var intrinsics.
|
|
for (Instruction &I : BB) {
|
|
if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I))
|
|
Dbgs.push_back(DVI);
|
|
}
|
|
}
|
|
|
|
for (auto &I : Dbgs)
|
|
I->eraseFromParent();
|
|
|
|
return true;
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
}
|
|
|
|
DebugValueDrop() : FunctionPass(ID) {}
|
|
};
|
|
|
|
struct DebugInfoDummyAnalysis : public FunctionPass {
|
|
static char ID;
|
|
bool runOnFunction(Function &F) override {
|
|
// Do nothing, so debug info stays untouched.
|
|
return false;
|
|
}
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesAll();
|
|
}
|
|
|
|
DebugInfoDummyAnalysis() : FunctionPass(ID) {}
|
|
};
|
|
}
|
|
|
|
char DebugInfoDrop::ID = 0;
|
|
char DebugValueDrop::ID = 0;
|
|
char DebugInfoDummyAnalysis::ID = 0;
|
|
|
|
TEST(DebugInfoDrop, DropOriginalDebugInfo) {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
|
define i16 @f(i16 %a) !dbg !6 {
|
|
%b = add i16 %a, 1, !dbg !11
|
|
call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
|
|
ret i16 0, !dbg !11
|
|
}
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!5}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
!1 = !DIFile(filename: "t.ll", directory: "/")
|
|
!2 = !{}
|
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
|
|
!7 = !DISubroutineType(types: !2)
|
|
!8 = !{!9}
|
|
!9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
|
|
!10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
|
|
!11 = !DILocation(line: 1, column: 1, scope: !6)
|
|
)");
|
|
|
|
DebugInfoDrop *P = new DebugInfoDrop();
|
|
|
|
DebugInfoPerPass DIBeforePass;
|
|
DebugifyCustomPassManager Passes;
|
|
Passes.setDebugInfoBeforePass(DIBeforePass);
|
|
Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
|
|
&(Passes.getDebugInfoPerPass())));
|
|
Passes.add(P);
|
|
Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
|
|
DebugifyMode::OriginalDebugInfo,
|
|
&(Passes.getDebugInfoPerPass())));
|
|
|
|
testing::internal::CaptureStderr();
|
|
Passes.run(*M);
|
|
|
|
std::string StdOut = testing::internal::GetCapturedStderr();
|
|
|
|
std::string ErrorForSP = "ERROR: dropped DISubprogram of";
|
|
std::string WarningForLoc = "WARNING: dropped DILocation of";
|
|
std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
|
|
|
|
EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
|
|
}
|
|
|
|
TEST(DebugValueDrop, DropOriginalDebugValues) {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
|
define i16 @f(i16 %a) !dbg !6 {
|
|
%b = add i16 %a, 1, !dbg !11
|
|
call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
|
|
ret i16 0, !dbg !11
|
|
}
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!5}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
!1 = !DIFile(filename: "t.ll", directory: "/")
|
|
!2 = !{}
|
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
|
|
!7 = !DISubroutineType(types: !2)
|
|
!8 = !{!9}
|
|
!9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
|
|
!10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
|
|
!11 = !DILocation(line: 1, column: 1, scope: !6)
|
|
)");
|
|
|
|
DebugValueDrop *P = new DebugValueDrop();
|
|
|
|
DebugInfoPerPass DIBeforePass;
|
|
DebugifyCustomPassManager Passes;
|
|
Passes.setDebugInfoBeforePass(DIBeforePass);
|
|
Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
|
|
&(Passes.getDebugInfoPerPass())));
|
|
Passes.add(P);
|
|
Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
|
|
DebugifyMode::OriginalDebugInfo,
|
|
&(Passes.getDebugInfoPerPass())));
|
|
|
|
testing::internal::CaptureStderr();
|
|
Passes.run(*M);
|
|
|
|
std::string StdOut = testing::internal::GetCapturedStderr();
|
|
|
|
std::string ErrorForSP = "ERROR: dropped DISubprogram of";
|
|
std::string WarningForLoc = "WARNING: dropped DILocation of";
|
|
std::string WarningForVars = "WARNING: drops dbg.value()/dbg.declare() for";
|
|
std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
|
|
|
|
EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(WarningForVars) != std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
|
|
}
|
|
|
|
TEST(DebugInfoDummyAnalysis, PreserveOriginalDebugInfo) {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
|
define i32 @g(i32 %b) !dbg !6 {
|
|
%c = add i32 %b, 1, !dbg !11
|
|
call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11
|
|
ret i32 1, !dbg !11
|
|
}
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!5}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
!1 = !DIFile(filename: "test.ll", directory: "/")
|
|
!2 = !{}
|
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
|
|
!7 = !DISubroutineType(types: !2)
|
|
!8 = !{!9}
|
|
!9 = !DILocalVariable(name: "c", scope: !6, file: !1, line: 1, type: !10)
|
|
!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
|
|
!11 = !DILocation(line: 1, column: 1, scope: !6)
|
|
)");
|
|
|
|
DebugInfoDummyAnalysis *P = new DebugInfoDummyAnalysis();
|
|
|
|
DebugInfoPerPass DIBeforePass;
|
|
DebugifyCustomPassManager Passes;
|
|
Passes.setDebugInfoBeforePass(DIBeforePass);
|
|
Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
|
|
&(Passes.getDebugInfoPerPass())));
|
|
Passes.add(P);
|
|
Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
|
|
DebugifyMode::OriginalDebugInfo,
|
|
&(Passes.getDebugInfoPerPass())));
|
|
|
|
testing::internal::CaptureStderr();
|
|
Passes.run(*M);
|
|
|
|
std::string StdOut = testing::internal::GetCapturedStderr();
|
|
|
|
std::string ErrorForSP = "ERROR: dropped DISubprogram of";
|
|
std::string WarningForLoc = "WARNING: dropped DILocation of";
|
|
std::string WarningForVars = "WARNING: drops dbg.value()/dbg.declare() for";
|
|
std::string FinalResult = "CheckModuleDebugify (original debuginfo): PASS";
|
|
|
|
EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(WarningForVars) == std::string::npos);
|
|
EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
|
|
}
|
|
|
|
} // end namespace llvm
|
|
|
|
INITIALIZE_PASS_BEGIN(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass",
|
|
false, false)
|
|
INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false,
|
|
false)
|
|
|
|
INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
|
|
"debuginfodummyanalysispass", false, false)
|
|
INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
|
|
"debuginfodummyanalysispass", false, false)
|