1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

Revert "[Debugify] Make the debugify aware of the original (-g) Debug Info"

This reverts rG8ee7c7e02953.
One test is failing, I'll reland this as soon as possible.
This commit is contained in:
Djordje Todorovic 2021-02-18 02:03:18 -08:00 committed by Djordje Todorovic
parent 60a660675e
commit 78cda129f4
7 changed files with 77 additions and 700 deletions

View File

@ -229,8 +229,8 @@ An IR test case for a transformation can, in many cases, be automatically
mutated to test debug info handling within that transformation. This is a
simple way to test for proper debug info handling.
The ``debugify`` utility pass
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``debugify`` utility
^^^^^^^^^^^^^^^^^^^^^^^^
The ``debugify`` testing utility is just a pair of passes: ``debugify`` and
``check-debugify``.
@ -346,21 +346,6 @@ tests. Changes to this pass are not allowed to break existing tests.
.. _MIRDebugify:
Test original debug info preservation in optimizations
------------------------------------------------------
In addition to automatically generating debug info, the checks provided by
the ``debugify`` utility pass can also be used to test the preservation of
pre-existing debug info metadata. It could be run as follows:
.. code-block:: bash
# Run the pass by checking original Debug Info preservation.
$ opt -verify-debuginfo-preserve -pass-to-test sample.ll
# Check the preservation of original Debug Info after each pass.
$ opt -verify-each-debuginfo-preserve -O2 sample.ll
Mutation testing for MIR-level transformations
----------------------------------------------

View File

@ -1,4 +1,4 @@
//===- Debugify.h - Check debug info preservation in optimizations --------===//
//===- Debugify.h - Attach synthetic debug info to everything -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@ -6,41 +6,19 @@
//
//===----------------------------------------------------------------------===//
///
/// \file Interface to the `debugify` synthetic/original debug info testing
/// utility.
/// \file Interface to the `debugify` synthetic debug info testing utility.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
#define LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
using DebugFnMap = llvm::DenseMap<llvm::StringRef, const llvm::DISubprogram *>;
using DebugInstMap = llvm::DenseMap<const llvm::Instruction *, bool>;
using WeakInstValueMap =
llvm::DenseMap<const llvm::Instruction *, llvm::WeakVH>;
/// Used to track the Debug Info Metadata information.
struct DebugInfoPerPass {
// This maps a function name to its associated DISubprogram.
DebugFnMap DIFunctions;
// This maps an instruction and the info about whether it has !dbg attached.
DebugInstMap DILocations;
// This tracks value (instruction) deletion. If an instruction gets deleted,
// WeakVH nulls itself.
WeakInstValueMap InstToDelete;
};
/// Map pass names to a per-pass DebugInfoPerPass instance.
using DebugInfoPerPassMap = llvm::MapVector<llvm::StringRef, DebugInfoPerPass>;
namespace llvm {
class DIBuilder;
@ -62,49 +40,14 @@ bool applyDebugifyMetadata(
/// Returns true if any change was made.
bool stripDebugifyMetadata(Module &M);
/// Collect original debug information before a pass.
///
/// \param M The module to collect debug information from.
/// \param Functions A range of functions to collect debug information from.
/// \param DIPreservationMap A map to collect the DI metadata.
/// \param Banner A prefix string to add to debug/error messages.
/// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
bool collectDebugInfoMetadata(Module &M,
iterator_range<Module::iterator> Functions,
DebugInfoPerPassMap &DIPreservationMap,
StringRef Banner, StringRef NameOfWrappedPass);
/// Check original debug information after a pass.
///
/// \param M The module to collect debug information from.
/// \param Functions A range of functions to collect debug information from.
/// \param DIPreservationMap A map used to check collected the DI metadata.
/// \param Banner A prefix string to add to debug/error messages.
/// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
bool checkDebugInfoMetadata(Module &M,
iterator_range<Module::iterator> Functions,
DebugInfoPerPassMap &DIPreservationMap,
StringRef Banner, StringRef NameOfWrappedPass);
} // namespace llvm
/// Used to check whether we track synthetic or original debug info.
enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
llvm::ModulePass *createDebugifyModulePass(
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
llvm::StringRef NameOfWrappedPass = "",
DebugInfoPerPassMap *DIPreservationMap = nullptr);
llvm::FunctionPass *createDebugifyFunctionPass(
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
llvm::StringRef NameOfWrappedPass = "",
DebugInfoPerPassMap *DIPreservationMap = nullptr);
llvm::ModulePass *createDebugifyModulePass();
llvm::FunctionPass *createDebugifyFunctionPass();
struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
};
/// Track how much `debugify` information (in the `synthetic` mode only)
/// has been lost.
/// Track how much `debugify` information has been lost.
struct DebugifyStatistics {
/// Number of missing dbg.values.
unsigned NumDbgValuesMissing = 0;
@ -132,26 +75,23 @@ struct DebugifyStatistics {
/// Map pass names to a per-pass DebugifyStatistics instance.
using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
llvm::ModulePass *createCheckDebugifyModulePass(
bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr);
void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
llvm::FunctionPass *createCheckDebugifyFunctionPass(
bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr);
llvm::ModulePass *
createCheckDebugifyModulePass(bool Strip = false,
llvm::StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr);
llvm::FunctionPass *
createCheckDebugifyFunctionPass(bool Strip = false,
llvm::StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr);
struct NewPMCheckDebugifyPass
: public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
};
namespace llvm {
void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
struct DebugifyEachInstrumentation {
DebugifyStatsMap StatsMap;
@ -163,9 +103,8 @@ struct DebugifyEachInstrumentation {
/// NOTE: We support legacy custom pass manager only.
/// TODO: Add New PM support for custom pass manager.
class DebugifyCustomPassManager : public legacy::PassManager {
DebugifyStatsMap *DIStatsMap = nullptr;
DebugInfoPerPassMap *DIPreservationMap = nullptr;
enum DebugifyMode Mode = DebugifyMode::NoDebugify;
DebugifyStatsMap DIStatsMap;
bool EnableDebugifyEach = false;
public:
using super = legacy::PassManager;
@ -173,34 +112,29 @@ public:
void add(Pass *P) override {
// Wrap each pass with (-check)-debugify passes if requested, making
// exceptions for passes which shouldn't see -debugify instrumentation.
bool WrapWithDebugify =
Mode != DebugifyMode::NoDebugify &&
!P->getAsImmutablePass() && !isIRPrintingPass(P) &&
!isBitcodeWriterPass(P);
bool WrapWithDebugify = EnableDebugifyEach && !P->getAsImmutablePass() &&
!isIRPrintingPass(P) && !isBitcodeWriterPass(P);
if (!WrapWithDebugify) {
super::add(P);
return;
}
// Either apply -debugify/-check-debugify before/after each pass and collect
// debug info loss statistics, or collect and check original debug info in
// the optimizations.
// Apply -debugify/-check-debugify before/after each pass and collect
// debug info loss statistics.
PassKind Kind = P->getPassKind();
StringRef Name = P->getPassName();
// TODO: Implement Debugify for LoopPass.
switch (Kind) {
case PT_Function:
super::add(createDebugifyFunctionPass(Mode, Name, DIPreservationMap));
super::add(createDebugifyFunctionPass());
super::add(P);
super::add(createCheckDebugifyFunctionPass(
isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DIPreservationMap));
super::add(createCheckDebugifyFunctionPass(true, Name, &DIStatsMap));
break;
case PT_Module:
super::add(createDebugifyModulePass(Mode, Name, DIPreservationMap));
super::add(createDebugifyModulePass());
super::add(P);
super::add(createCheckDebugifyModulePass(
isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DIPreservationMap));
super::add(createCheckDebugifyModulePass(true, Name, &DIStatsMap));
break;
default:
super::add(P);
@ -208,23 +142,9 @@ public:
}
}
// Used within DebugifyMode::SyntheticDebugInfo mode.
void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
// Used within DebugifyMode::OriginalDebugInfo mode.
void setDIPreservationMap(DebugInfoPerPassMap &PerPassMap) {
DIPreservationMap = &PerPassMap;
}
void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
void enableDebugifyEach() { EnableDebugifyEach = true; }
bool isSyntheticDebugInfo() const {
return Mode == DebugifyMode::SyntheticDebugInfo;
}
bool isOriginalDebugInfoMode() const {
return Mode == DebugifyMode::OriginalDebugInfo;
}
const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
DebugInfoPerPassMap &getDebugInfoPerPassMap() { return *DIPreservationMap; }
const DebugifyStatsMap &getDebugifyStatsMap() const { return DIStatsMap; }
};
} // namespace llvm

View File

@ -1,4 +1,4 @@
//===- Debugify.cpp - Check debug info preservation in optimizations ------===//
//===- Debugify.cpp - Attach synthetic debug info to everything -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@ -6,10 +6,8 @@
//
//===----------------------------------------------------------------------===//
///
/// \file In the `synthetic` mode, the `-debugify` attaches synthetic debug info
/// to everything. It can be used to create targeted tests for debug info
/// preservation. In addition, when using the `original` mode, it can check
/// original debug info preservation. The `synthetic` mode is default one.
/// \file This pass attaches synthetic debug info to everything. It can be used
/// to create targeted tests for debug info preservation.
///
//===----------------------------------------------------------------------===//
@ -26,8 +24,6 @@
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#define DEBUG_TYPE "debugify"
using namespace llvm;
namespace {
@ -39,8 +35,6 @@ enum class Level {
Locations,
LocationsAndVariables
};
// Used for the synthetic mode only.
cl::opt<Level> DebugifyLevel(
"debugify-level", cl::desc("Kind of debug info to add"),
cl::values(clEnumValN(Level::Locations, "locations", "Locations only"),
@ -205,33 +199,16 @@ bool llvm::applyDebugifyMetadata(
return true;
}
static bool
applyDebugify(Function &F,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr,
StringRef NameOfWrappedPass = "") {
static bool applyDebugify(Function &F) {
Module &M = *F.getParent();
auto FuncIt = F.getIterator();
if (Mode == DebugifyMode::SyntheticDebugInfo)
return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
"FunctionDebugify: ", /*ApplyToMF*/ nullptr);
assert(DIPreservationMap);
return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
"FunctionDebugify (original debuginfo)",
NameOfWrappedPass);
return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
"FunctionDebugify: ", /*ApplyToMF=*/nullptr);
}
static bool
applyDebugify(Module &M,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr,
StringRef NameOfWrappedPass = "") {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return applyDebugifyMetadata(M, M.functions(),
"ModuleDebugify: ", /*ApplyToMF*/ nullptr);
return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
"ModuleDebugify (original debuginfo)",
NameOfWrappedPass);
static bool applyDebugify(Module &M) {
return applyDebugifyMetadata(M, M.functions(),
"ModuleDebugify: ", /*ApplyToMF=*/nullptr);
}
bool llvm::stripDebugifyMetadata(Module &M) {
@ -279,211 +256,6 @@ bool llvm::stripDebugifyMetadata(Module &M) {
return Changed;
}
bool llvm::collectDebugInfoMetadata(Module &M,
iterator_range<Module::iterator> Functions,
DebugInfoPerPassMap &DIPreservationMap,
StringRef Banner,
StringRef NameOfWrappedPass) {
LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');
// Clear the map with the debug info before every single pass.
DIPreservationMap.clear();
if (!M.getNamedMetadata("llvm.dbg.cu")) {
dbg() << Banner << ": Skipping module without debug info\n";
return false;
}
// Visit each instruction.
for (Function &F : Functions) {
if (isFunctionSkipped(F))
continue;
// Collect the DISubprogram.
auto *SP = F.getSubprogram();
DIPreservationMap[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP});
if (SP)
LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
for (BasicBlock &BB : F) {
// Collect debug locations (!dbg).
// TODO: Collect dbg.values.
for (Instruction &I : BB) {
// Skip PHIs.
if (isa<PHINode>(I))
continue;
// Skip debug instructions.
if (isa<DbgInfoIntrinsic>(&I))
continue;
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
DIPreservationMap[NameOfWrappedPass].InstToDelete.insert({&I, &I});
const DILocation *Loc = I.getDebugLoc().get();
bool HasLoc = Loc != nullptr;
DIPreservationMap[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
}
}
}
return true;
}
// This checks the preservation of original debug info attached to functions.
static bool checkFunctions(const DebugFnMap &DIFunctionsBefore,
const DebugFnMap &DIFunctionsAfter,
StringRef NameOfWrappedPass,
StringRef FileNameFromCU) {
bool Preserved = true;
for (const auto &F : DIFunctionsAfter) {
if (F.second)
continue;
auto SPIt = DIFunctionsBefore.find(F.first);
if (SPIt == DIFunctionsBefore.end()) {
dbg() << "ERROR: " << NameOfWrappedPass
<< " did not generate DISubprogram for " << F.first << " from "
<< FileNameFromCU << '\n';
Preserved = false;
} else {
auto SP = SPIt->second;
if (!SP)
continue;
// If the function had the SP attached before the pass, consider it as
// a debug info bug.
dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "
<< F.first << " from " << FileNameFromCU << '\n';
Preserved = false;
}
}
return Preserved;
}
// This checks the preservation of the original debug info attached to
// instructions.
static bool checkInstructions(const DebugInstMap &DILocsBefore,
const DebugInstMap &DILocsAfter,
const WeakInstValueMap &InstToDelete,
StringRef NameOfWrappedPass,
StringRef FileNameFromCU) {
bool Preserved = true;
for (const auto &L : DILocsAfter) {
if (L.second)
continue;
auto Instr = L.first;
// In order to avoid pointer reuse/recycling, skip the values that might
// have been deleted during a pass.
auto WeakInstrPtr = InstToDelete.find(Instr);
if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
continue;
auto FnName = Instr->getFunction()->getName();
auto BB = Instr->getParent();
auto BBName = BB->hasName() ? BB->getName() : "no-name";
auto InstrIt = DILocsBefore.find(Instr);
if (InstrIt == DILocsBefore.end()) {
dbg() << "WARNING: " << NameOfWrappedPass
<< " did not generate DILocation for " << *Instr
<< " (BB: " << BBName << ", Fn: " << FnName
<< ", File: " << FileNameFromCU << ")\n";
Preserved = false;
} else {
if (!InstrIt->second)
continue;
// If the instr had the !dbg attached before the pass, consider it as
// a debug info issue.
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
<< ", File: " << FileNameFromCU << ")\n";
Preserved = false;
}
}
return Preserved;
}
bool llvm::checkDebugInfoMetadata(Module &M,
iterator_range<Module::iterator> Functions,
DebugInfoPerPassMap &DIPreservationMap,
StringRef Banner,
StringRef NameOfWrappedPass) {
LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');
if (!M.getNamedMetadata("llvm.dbg.cu")) {
dbg() << Banner << ": Skipping module without debug info\n";
return false;
}
// Map the debug info holding DIs after a pass.
DebugInfoPerPassMap DIPreservationAfter;
// Visit each instruction.
for (Function &F : Functions) {
if (isFunctionSkipped(F))
continue;
// TODO: Collect metadata other than DISubprograms.
// Collect the DISubprogram.
auto *SP = F.getSubprogram();
DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP});
if (SP)
LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
for (BasicBlock &BB : F) {
// Collect debug locations (!dbg attachments).
// TODO: Collect dbg.values.
for (Instruction &I : BB) {
// Skip PHIs.
if (isa<PHINode>(I))
continue;
// Skip debug instructions.
if (isa<DbgInfoIntrinsic>(&I))
continue;
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
const DILocation *Loc = I.getDebugLoc().get();
bool HasLoc = Loc != nullptr;
DIPreservationAfter[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
}
}
}
// TODO: The name of the module could be read better?
StringRef FileNameFromCU =
(cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
->getFilename();
auto DIFunctionsBefore = DIPreservationMap[NameOfWrappedPass].DIFunctions;
auto DIFunctionsAfter = DIPreservationAfter[NameOfWrappedPass].DIFunctions;
auto DILocsBefore = DIPreservationMap[NameOfWrappedPass].DILocations;
auto DILocsAfter = DIPreservationAfter[NameOfWrappedPass].DILocations;
auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete;
bool ResultForFunc = checkFunctions(DIFunctionsBefore, DIFunctionsAfter,
NameOfWrappedPass, FileNameFromCU);
bool ResultForInsts =
checkInstructions(DILocsBefore, DILocsAfter, InstToDelete,
NameOfWrappedPass, FileNameFromCU);
bool Result = ResultForFunc && ResultForInsts;
StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;
if (Result)
dbg() << ResultBanner << ": PASS\n";
else
dbg() << ResultBanner << ": FAIL\n";
LLVM_DEBUG(dbgs() << "\n\n");
return Result;
}
namespace {
/// Return true if a mis-sized diagnostic is issued for \p DVI.
bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
@ -622,74 +394,43 @@ bool checkDebugifyMetadata(Module &M,
/// ModulePass for attaching synthetic debug info to everything, used with the
/// legacy module pass manager.
struct DebugifyModulePass : public ModulePass {
bool runOnModule(Module &M) override {
return applyDebugify(M, Mode, DIPreservationMap, NameOfWrappedPass);
}
bool runOnModule(Module &M) override { return applyDebugify(M); }
DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
StringRef NameOfWrappedPass = "",
DebugInfoPerPassMap *DIPreservationMap = nullptr)
: ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
DIPreservationMap(DIPreservationMap), Mode(Mode) {}
DebugifyModulePass() : ModulePass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
static char ID; // Pass identification.
private:
StringRef NameOfWrappedPass;
DebugInfoPerPassMap *DIPreservationMap;
enum DebugifyMode Mode;
};
/// FunctionPass for attaching synthetic debug info to instructions within a
/// single function, used with the legacy module pass manager.
struct DebugifyFunctionPass : public FunctionPass {
bool runOnFunction(Function &F) override {
return applyDebugify(F, Mode, DIPreservationMap, NameOfWrappedPass);
}
bool runOnFunction(Function &F) override { return applyDebugify(F); }
DebugifyFunctionPass(
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
StringRef NameOfWrappedPass = "",
DebugInfoPerPassMap *DIPreservationMap = nullptr)
: FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
DIPreservationMap(DIPreservationMap), Mode(Mode) {}
DebugifyFunctionPass() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
static char ID; // Pass identification.
private:
StringRef NameOfWrappedPass;
DebugInfoPerPassMap *DIPreservationMap;
enum DebugifyMode Mode;
};
/// ModulePass for checking debug info inserted by -debugify, used with the
/// legacy module pass manager.
struct CheckDebugifyModulePass : public ModulePass {
bool runOnModule(Module &M) override {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
"CheckModuleDebugify", Strip, StatsMap);
return checkDebugInfoMetadata(
M, M.functions(), *DIPreservationMap,
"CheckModuleDebugify (original debuginfo)", NameOfWrappedPass);
return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
"CheckModuleDebugify", Strip, StatsMap);
}
CheckDebugifyModulePass(
bool Strip = false, StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr)
: ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
Strip(Strip) {}
CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr)
: ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
StatsMap(StatsMap) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@ -698,11 +439,9 @@ struct CheckDebugifyModulePass : public ModulePass {
static char ID; // Pass identification.
private:
bool Strip;
StringRef NameOfWrappedPass;
DebugifyStatsMap *StatsMap;
DebugInfoPerPassMap *DIPreservationMap;
enum DebugifyMode Mode;
bool Strip;
};
/// FunctionPass for checking debug info inserted by -debugify-function, used
@ -711,23 +450,16 @@ struct CheckDebugifyFunctionPass : public FunctionPass {
bool runOnFunction(Function &F) override {
Module &M = *F.getParent();
auto FuncIt = F.getIterator();
if (Mode == DebugifyMode::SyntheticDebugInfo)
return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
NameOfWrappedPass, "CheckFunctionDebugify",
Strip, StatsMap);
return checkDebugInfoMetadata(
M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap,
"CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass);
return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
NameOfWrappedPass, "CheckFunctionDebugify",
Strip, StatsMap);
}
CheckDebugifyFunctionPass(
bool Strip = false, StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr,
enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
DebugInfoPerPassMap *DIPreservationMap = nullptr)
: FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
Strip(Strip) {}
CheckDebugifyFunctionPass(bool Strip = false,
StringRef NameOfWrappedPass = "",
DebugifyStatsMap *StatsMap = nullptr)
: FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
StatsMap(StatsMap) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@ -736,11 +468,9 @@ struct CheckDebugifyFunctionPass : public FunctionPass {
static char ID; // Pass identification.
private:
bool Strip;
StringRef NameOfWrappedPass;
DebugifyStatsMap *StatsMap;
DebugInfoPerPassMap *DIPreservationMap;
enum DebugifyMode Mode;
bool Strip;
};
} // end anonymous namespace
@ -766,23 +496,12 @@ void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) {
}
}
ModulePass *createDebugifyModulePass(enum DebugifyMode Mode,
llvm::StringRef NameOfWrappedPass,
DebugInfoPerPassMap *DIPreservationMap) {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return new DebugifyModulePass();
assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
return new DebugifyModulePass(Mode, NameOfWrappedPass, DIPreservationMap);
ModulePass *llvm::createDebugifyModulePass() {
return new DebugifyModulePass();
}
FunctionPass *
createDebugifyFunctionPass(enum DebugifyMode Mode,
llvm::StringRef NameOfWrappedPass,
DebugInfoPerPassMap *DIPreservationMap) {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return new DebugifyFunctionPass();
assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap);
FunctionPass *llvm::createDebugifyFunctionPass() {
return new DebugifyFunctionPass();
}
PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
@ -791,24 +510,16 @@ PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
return PreservedAnalyses::all();
}
ModulePass *createCheckDebugifyModulePass(
bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap) {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,
DIPreservationMap);
ModulePass *llvm::createCheckDebugifyModulePass(bool Strip,
StringRef NameOfWrappedPass,
DebugifyStatsMap *StatsMap) {
return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
}
FunctionPass *createCheckDebugifyFunctionPass(
bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap) {
if (Mode == DebugifyMode::SyntheticDebugInfo)
return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,
DIPreservationMap);
FunctionPass *
llvm::createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass,
DebugifyStatsMap *StatsMap) {
return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
}
PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,

View File

@ -1,23 +0,0 @@
; 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
; ModuleID = 'no-dbg-info.c'
source_filename = "no-dbg-info.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: nounwind uwtable
define dso_local i32 @fn() {
%1 = call i32 (...) @fn2()
ret i32 %1
}
declare dso_local i32 @fn2(...)
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 11.0.0"}

View File

@ -219,16 +219,6 @@ static cl::opt<bool> EnableDebugify(
cl::desc(
"Start the pipeline with debugify and end it with check-debugify"));
static cl::opt<bool> VerifyDebugInfoPreserve(
"verify-debuginfo-preserve",
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<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
@ -823,19 +813,10 @@ int main(int argc, char **argv) {
// about to build. If the -debugify-each option is set, wrap each pass with
// the (-check)-debugify passes.
DebugifyCustomPassManager Passes;
DebugifyStatsMap DIStatsMap;
DebugInfoPerPassMap DIPreservationMap;
if (DebugifyEach) {
Passes.setDebugifyMode(DebugifyMode::SyntheticDebugInfo);
Passes.setDIStatsMap(DIStatsMap);
} else if (VerifyEachDebugInfoPreserve) {
Passes.setDebugifyMode(DebugifyMode::OriginalDebugInfo);
Passes.setDIPreservationMap(DIPreservationMap);
}
if (DebugifyEach)
Passes.enableDebugifyEach();
bool AddOneTimeDebugifyPasses =
(EnableDebugify && !DebugifyEach) ||
(VerifyDebugInfoPreserve && !VerifyEachDebugInfoPreserve);
bool AddOneTimeDebugifyPasses = EnableDebugify && !DebugifyEach;
Passes.add(new TargetLibraryInfoWrapperPass(TLII));
@ -843,17 +824,8 @@ int main(int argc, char **argv) {
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
if (AddOneTimeDebugifyPasses) {
if (EnableDebugify) {
Passes.setDIStatsMap(DIStatsMap);
Passes.add(createDebugifyModulePass());
} else if (VerifyDebugInfoPreserve) {
Passes.setDIPreservationMap(DIPreservationMap);
Passes.add(createDebugifyModulePass(
DebugifyMode::OriginalDebugInfo, "",
&(Passes.getDebugInfoPerPassMap())));
}
}
if (AddOneTimeDebugifyPasses)
Passes.add(createDebugifyModulePass());
std::unique_ptr<legacy::FunctionPassManager> FPasses;
if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz ||
@ -997,14 +969,8 @@ int main(int argc, char **argv) {
if (!NoVerify && !VerifyEach)
Passes.add(createVerifierPass());
if (AddOneTimeDebugifyPasses) {
if (EnableDebugify)
Passes.add(createCheckDebugifyModulePass(false));
else if (VerifyDebugInfoPreserve)
Passes.add(createCheckDebugifyModulePass(
false, "", nullptr, DebugifyMode::OriginalDebugInfo,
&(Passes.getDebugInfoPerPassMap())));
}
if (AddOneTimeDebugifyPasses)
Passes.add(createCheckDebugifyModulePass(false));
// In run twice mode, we want to make sure the output is bit-by-bit
// equivalent if we run the pass manager again, so setup two buffers and

View File

@ -1,7 +1,6 @@
set(LLVM_LINK_COMPONENTS
Analysis
AsmParser
BitWriter
Core
Support
TransformUtils
@ -14,7 +13,6 @@ add_llvm_unittest(UtilsTests
CloningTest.cpp
CodeExtractorTest.cpp
CodeMoverUtilsTest.cpp
DebugifyTest.cpp
FunctionComparatorTest.cpp
IntegerDivisionTest.cpp
LocalTest.cpp

View File

@ -1,180 +0,0 @@
//===- 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/AsmParser/Parser.h"
#include "llvm/IR/DebugInfoMetadata.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 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 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();
DebugInfoPerPassMap DIPreservationMap;
DebugifyCustomPassManager Passes;
Passes.setDIPreservationMap(DIPreservationMap);
Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
&(Passes.getDebugInfoPerPassMap())));
Passes.add(P);
Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
DebugifyMode::OriginalDebugInfo,
&(Passes.getDebugInfoPerPassMap())));
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(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();
DebugInfoPerPassMap DIPreservationMap;
DebugifyCustomPassManager Passes;
Passes.setDIPreservationMap(DIPreservationMap);
Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
&(Passes.getDebugInfoPerPassMap())));
Passes.add(P);
Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
DebugifyMode::OriginalDebugInfo,
&(Passes.getDebugInfoPerPassMap())));
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): PASS";
EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
EXPECT_TRUE(StdOut.find(WarningForLoc) == 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)