summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/IR/IRPrintingPasses.h4
-rw-r--r--llvm/lib/IR/IRPrintingPasses.cpp8
-rw-r--r--llvm/test/DebugInfo/debugify-each.ll24
-rw-r--r--llvm/test/DebugInfo/debugify.ll20
-rw-r--r--llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll2
-rw-r--r--llvm/tools/opt/Debugify.cpp164
-rw-r--r--llvm/tools/opt/PassPrinters.h6
-rw-r--r--llvm/tools/opt/opt.cpp48
8 files changed, 218 insertions, 58 deletions
diff --git a/llvm/include/llvm/IR/IRPrintingPasses.h b/llvm/include/llvm/IR/IRPrintingPasses.h
index 550edc75fce..e4ac5d4d88a 100644
--- a/llvm/include/llvm/IR/IRPrintingPasses.h
+++ b/llvm/include/llvm/IR/IRPrintingPasses.h
@@ -23,6 +23,7 @@
#include <string>
namespace llvm {
+class Pass;
class BasicBlockPass;
class Function;
class FunctionPass;
@@ -54,6 +55,9 @@ BasicBlockPass *createPrintBasicBlockPass(raw_ostream &OS,
/// non-printable characters in it.
void printLLVMNameWithoutPrefix(raw_ostream &OS, StringRef Name);
+/// Return true if a pass is for IR printing.
+bool isIRPrintingPass(Pass *P);
+
/// Pass for printing a Module as LLVM's text IR assembly.
///
/// Note: This pass is for use with the new pass manager. Use the create...Pass
diff --git a/llvm/lib/IR/IRPrintingPasses.cpp b/llvm/lib/IR/IRPrintingPasses.cpp
index 3b32814bed5..2aff2f2ebe4 100644
--- a/llvm/lib/IR/IRPrintingPasses.cpp
+++ b/llvm/lib/IR/IRPrintingPasses.cpp
@@ -150,3 +150,11 @@ BasicBlockPass *llvm::createPrintBasicBlockPass(llvm::raw_ostream &OS,
const std::string &Banner) {
return new PrintBasicBlockPass(OS, Banner);
}
+
+bool llvm::isIRPrintingPass(Pass *P) {
+ const char *PID = (const char*)P->getPassID();
+
+ return (PID == &PrintModulePassWrapper::ID)
+ || (PID == &PrintFunctionPassWrapper::ID)
+ || (PID == &PrintBasicBlockPass::ID);
+}
diff --git a/llvm/test/DebugInfo/debugify-each.ll b/llvm/test/DebugInfo/debugify-each.ll
new file mode 100644
index 00000000000..569c629e115
--- /dev/null
+++ b/llvm/test/DebugInfo/debugify-each.ll
@@ -0,0 +1,24 @@
+; RUN: opt -debugify-each -O3 -S -o - < %s | FileCheck %s
+; RUN: opt -debugify-each -instrprof -sroa -sccp -S -o - < %s | FileCheck %s
+
+define void @foo() {
+ ret void
+}
+
+define void @bar() {
+ ret void
+}
+
+; Verify that the module & function (check-)debugify passes run at least twice.
+
+; CHECK-DAG: CheckModuleDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+
+; CHECK-DAG: CheckModuleDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
+; CHECK-DAG: CheckFunctionDebugify: PASS
diff --git a/llvm/test/DebugInfo/debugify.ll b/llvm/test/DebugInfo/debugify.ll
index 0221a00aaef..6d81bb87a26 100644
--- a/llvm/test/DebugInfo/debugify.ll
+++ b/llvm/test/DebugInfo/debugify.ll
@@ -7,11 +7,11 @@
; RUN: FileCheck %s -check-prefix=CHECK-REPEAT
; RUN: opt -debugify -check-debugify -S -o - < %s | \
-; RUN: FileCheck %s -implicit-check-not="CheckDebugify: FAIL"
+; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL"
; RUN: opt -passes=debugify,check-debugify -S -o - < %s | \
-; RUN: FileCheck %s -implicit-check-not="CheckDebugify: FAIL"
+; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL"
; RUN: opt -enable-debugify -passes=verify -S -o - < %s | \
-; RUN: FileCheck %s -implicit-check-not="CheckDebugify: FAIL"
+; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL"
; RUN: opt -debugify -strip -check-debugify -S -o - < %s | \
; RUN: FileCheck %s -check-prefix=CHECK-FAIL
@@ -68,18 +68,18 @@ define weak_odr zeroext i1 @baz() {
; CHECK-DAG: ![[NUM_VARS]] = !{i32 1}
; --- Repeat case
-; CHECK-REPEAT: Debugify: Skipping module with debug info
+; CHECK-REPEAT: ModuleDebugify: Skipping module with debug info
; --- Failure case
-; CHECK-FAIL: ERROR: Instruction with empty DebugLoc -- ret void
-; CHECK-FAIL: ERROR: Instruction with empty DebugLoc -- call void @foo()
-; CHECK-FAIL: ERROR: Instruction with empty DebugLoc -- {{.*}} add i32 0, 1
-; CHECK-FAIL: ERROR: Instruction with empty DebugLoc -- ret i32 0
+; CHECK-FAIL: ERROR: Instruction with empty DebugLoc in function foo -- ret void
+; CHECK-FAIL: ERROR: Instruction with empty DebugLoc in function bar -- call void @foo()
+; CHECK-FAIL: ERROR: Instruction with empty DebugLoc in function bar -- {{.*}} add i32 0, 1
+; CHECK-FAIL: ERROR: Instruction with empty DebugLoc in function bar -- ret i32 0
; CHECK-FAIL: WARNING: Missing line 1
; CHECK-FAIL: WARNING: Missing line 2
; CHECK-FAIL: WARNING: Missing line 3
; CHECK-FAIL: WARNING: Missing line 4
; CHECK-FAIL: ERROR: Missing variable 1
-; CHECK-FAIL: CheckDebugify: FAIL
+; CHECK-FAIL: CheckModuleDebugify: FAIL
-; PASS: CheckDebugify: PASS
+; PASS: CheckModuleDebugify: PASS
diff --git a/llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll b/llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll
index a15be3854db..936285aa399 100644
--- a/llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll
+++ b/llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll
@@ -2,7 +2,7 @@
; RUN: opt < %s -debugify -mem2reg -check-debugify -S | FileCheck %s
; CHECK-NOT: alloca
-; CHECK: CheckDebugify: PASS
+; CHECK: CheckModuleDebugify: PASS
define double @testfunc(i32 %i, double %j) {
%I = alloca i32 ; <i32*> [#uses=4]
diff --git a/llvm/tools/opt/Debugify.cpp b/llvm/tools/opt/Debugify.cpp
index 441fec36765..135a026da49 100644
--- a/llvm/tools/opt/Debugify.cpp
+++ b/llvm/tools/opt/Debugify.cpp
@@ -39,10 +39,12 @@ bool isFunctionSkipped(Function &F) {
return F.isDeclaration() || !F.hasExactDefinition();
}
-bool applyDebugifyMetadata(Module &M) {
+bool applyDebugifyMetadata(Module &M,
+ iterator_range<Module::iterator> Functions,
+ StringRef Banner) {
// Skip modules with debug info.
if (M.getNamedMetadata("llvm.dbg.cu")) {
- errs() << "Debugify: Skipping module with debug info\n";
+ errs() << Banner << "Skipping module with debug info\n";
return false;
}
@@ -65,12 +67,11 @@ bool applyDebugifyMetadata(Module &M) {
unsigned NextLine = 1;
unsigned NextVar = 1;
auto File = DIB.createFile(M.getName(), "/");
- auto CU =
- DIB.createCompileUnit(dwarf::DW_LANG_C, DIB.createFile(M.getName(), "/"),
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File,
"debugify", /*isOptimized=*/true, "", 0);
// Visit each instruction.
- for (Function &F : M) {
+ for (Function &F : Functions) {
if (isFunctionSkipped(F))
continue;
@@ -118,54 +119,57 @@ bool applyDebugifyMetadata(Module &M) {
};
addDebugifyOperand(NextLine - 1); // Original number of lines.
addDebugifyOperand(NextVar - 1); // Original number of variables.
+ assert(NMD->getNumOperands() == 2 &&
+ "llvm.debugify should have exactly 2 operands!");
return true;
}
-void checkDebugifyMetadata(Module &M) {
+bool checkDebugifyMetadata(Module &M,
+ iterator_range<Module::iterator> Functions,
+ StringRef Banner,
+ bool Strip) {
// Skip modules without debugify metadata.
NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
- if (!NMD)
- return;
+ if (!NMD) {
+ errs() << Banner << "Skipping module without debugify metadata\n";
+ return false;
+ }
auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
->getZExtValue();
};
+ assert(NMD->getNumOperands() == 2 &&
+ "llvm.debugify should have exactly 2 operands!");
unsigned OriginalNumLines = getDebugifyOperand(0);
unsigned OriginalNumVars = getDebugifyOperand(1);
bool HasErrors = false;
- // Find missing lines.
BitVector MissingLines{OriginalNumLines, true};
- for (Function &F : M) {
+ BitVector MissingVars{OriginalNumVars, true};
+ for (Function &F : Functions) {
if (isFunctionSkipped(F))
continue;
+ // Find missing lines.
for (Instruction &I : instructions(F)) {
if (isa<DbgValueInst>(&I))
continue;
auto DL = I.getDebugLoc();
- if (DL) {
+ if (DL && DL.getLine() != 0) {
MissingLines.reset(DL.getLine() - 1);
continue;
}
- outs() << "ERROR: Instruction with empty DebugLoc -- ";
+ outs() << "ERROR: Instruction with empty DebugLoc in function ";
+ outs() << F.getName() << " --";
I.print(outs());
outs() << "\n";
HasErrors = true;
}
- }
- for (unsigned Idx : MissingLines.set_bits())
- outs() << "WARNING: Missing line " << Idx + 1 << "\n";
-
- // Find missing variables.
- BitVector MissingVars{OriginalNumVars, true};
- for (Function &F : M) {
- if (isFunctionSkipped(F))
- continue;
+ // Find missing variables.
for (Instruction &I : instructions(F)) {
auto *DVI = dyn_cast<DbgValueInst>(&I);
if (!DVI)
@@ -177,18 +181,39 @@ void checkDebugifyMetadata(Module &M) {
MissingVars.reset(Var - 1);
}
}
+
+ // Print the results.
+ for (unsigned Idx : MissingLines.set_bits())
+ outs() << "WARNING: Missing line " << Idx + 1 << "\n";
+
for (unsigned Idx : MissingVars.set_bits())
outs() << "ERROR: Missing variable " << Idx + 1 << "\n";
HasErrors |= MissingVars.count() > 0;
- outs() << "CheckDebugify: " << (HasErrors ? "FAIL" : "PASS") << "\n";
+ outs() << Banner << (HasErrors ? "FAIL" : "PASS") << '\n';
+ if (HasErrors) {
+ outs() << "Module IR Dump\n";
+ M.print(outs(), nullptr, false);
+ }
+
+ // Strip the Debugify Metadata if required.
+ if (Strip) {
+ StripDebugInfo(M);
+ M.eraseNamedMetadata(NMD);
+ return true;
+ }
+
+ return false;
}
-/// Attach synthetic debug info to everything.
-struct DebugifyPass : public ModulePass {
- bool runOnModule(Module &M) override { return applyDebugifyMetadata(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 applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
+ }
- DebugifyPass() : ModulePass(ID) {}
+ DebugifyModulePass() : ModulePass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@@ -197,43 +222,104 @@ struct DebugifyPass : public ModulePass {
static char ID; // Pass identification.
};
-/// Check debug info inserted by -debugify for completeness.
-struct CheckDebugifyPass : public ModulePass {
+/// 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 {
+ Module &M = *F.getParent();
+ auto FuncIt = F.getIterator();
+ return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
+ "FunctionDebugify: ");
+ }
+
+ DebugifyFunctionPass() : FunctionPass(ID) {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ static char ID; // Pass identification.
+};
+
+/// ModulePass for checking debug info inserted by -debugify, used with the
+/// legacy module pass manager.
+struct CheckDebugifyModulePass : public ModulePass {
bool runOnModule(Module &M) override {
- checkDebugifyMetadata(M);
- return false;
+ return checkDebugifyMetadata(M, M.functions(), "CheckModuleDebugify: ",
+ Strip);
}
- CheckDebugifyPass() : ModulePass(ID) {}
+ CheckDebugifyModulePass(bool Strip = false) : ModulePass(ID), Strip(Strip) {}
+
+ static char ID; // Pass identification.
+
+private:
+ bool Strip;
+};
+
+/// FunctionPass for checking debug info inserted by -debugify-function, used
+/// with the legacy module pass manager.
+struct CheckDebugifyFunctionPass : public FunctionPass {
+ bool runOnFunction(Function &F) override {
+ Module &M = *F.getParent();
+ auto FuncIt = F.getIterator();
+ return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
+ "CheckFunctionDebugify: ", Strip);
+ }
+
+ CheckDebugifyFunctionPass(bool Strip = false) : FunctionPass(ID), Strip(Strip) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
static char ID; // Pass identification.
+
+private:
+ bool Strip;
};
} // end anonymous namespace
-ModulePass *createDebugifyPass() { return new DebugifyPass(); }
+ModulePass *createDebugifyModulePass() {
+ return new DebugifyModulePass();
+}
+
+FunctionPass *createDebugifyFunctionPass() {
+ return new DebugifyFunctionPass();
+}
PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
- applyDebugifyMetadata(M);
+ applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
return PreservedAnalyses::all();
}
-ModulePass *createCheckDebugifyPass() { return new CheckDebugifyPass(); }
+ModulePass *createCheckDebugifyModulePass(bool Strip) {
+ return new CheckDebugifyModulePass(Strip);
+}
+
+FunctionPass *createCheckDebugifyFunctionPass(bool Strip) {
+ return new CheckDebugifyFunctionPass(Strip);
+}
PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
ModuleAnalysisManager &) {
- checkDebugifyMetadata(M);
+ checkDebugifyMetadata(M, M.functions(), "CheckModuleDebugify: ", false);
return PreservedAnalyses::all();
}
-char DebugifyPass::ID = 0;
-static RegisterPass<DebugifyPass> X("debugify",
+char DebugifyModulePass::ID = 0;
+static RegisterPass<DebugifyModulePass> DM("debugify",
"Attach debug info to everything");
-char CheckDebugifyPass::ID = 0;
-static RegisterPass<CheckDebugifyPass> Y("check-debugify",
+char CheckDebugifyModulePass::ID = 0;
+static RegisterPass<CheckDebugifyModulePass> CDM("check-debugify",
"Check debug info from -debugify");
+
+char DebugifyFunctionPass::ID = 0;
+static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
+ "Attach debug info to a function");
+
+char CheckDebugifyFunctionPass::ID = 0;
+static RegisterPass<CheckDebugifyFunctionPass> CDF("check-debugify-function",
+ "Check debug info from -debugify-function");
diff --git a/llvm/tools/opt/PassPrinters.h b/llvm/tools/opt/PassPrinters.h
index 1b0cea00835..e5c4110398f 100644
--- a/llvm/tools/opt/PassPrinters.h
+++ b/llvm/tools/opt/PassPrinters.h
@@ -49,13 +49,15 @@ BasicBlockPass *createBasicBlockPassPrinter(const PassInfo *PI,
} // end namespace llvm
-llvm::ModulePass *createDebugifyPass();
+llvm::ModulePass *createDebugifyModulePass();
+llvm::FunctionPass *createDebugifyFunctionPass();
struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
};
-llvm::ModulePass *createCheckDebugifyPass();
+llvm::ModulePass *createCheckDebugifyModulePass(bool Strip = false);
+llvm::FunctionPass *createCheckDebugifyFunctionPass(bool Strip = false);
struct NewPMCheckDebugifyPass
: public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 3e5499f90b9..f55509db218 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -207,6 +207,11 @@ static cl::opt<bool> EnableDebugify(
cl::desc(
"Start the pipeline with debugify and end it with check-debugify"));
+static cl::opt<bool> DebugifyEach(
+ "debugify-each",
+ cl::desc(
+ "Start each pass with debugify and end it with check-debugify"));
+
static cl::opt<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
@@ -256,6 +261,37 @@ static cl::opt<std::string>
cl::desc("YAML output filename for pass remarks"),
cl::value_desc("filename"));
+class OptCustomPassManager : public legacy::PassManager {
+public:
+ using super = legacy::PassManager;
+
+ void add(Pass *P) override {
+ bool WrapWithDebugify =
+ DebugifyEach && !P->getAsImmutablePass() && !isIRPrintingPass(P);
+ if (!WrapWithDebugify) {
+ super::add(P);
+ return;
+ }
+ PassKind Kind = P->getPassKind();
+ // TODO: Implement Debugify for BasicBlockPass, LoopPass.
+ switch (Kind) {
+ case PT_Function:
+ super::add(createDebugifyFunctionPass());
+ super::add(P);
+ super::add(createCheckDebugifyFunctionPass(true));
+ break;
+ case PT_Module:
+ super::add(createDebugifyModulePass());
+ super::add(P);
+ super::add(createCheckDebugifyModulePass(true));
+ break;
+ default:
+ super::add(P);
+ break;
+ }
+ }
+};
+
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
// Add the pass to the pass manager...
PM.add(P);
@@ -556,8 +592,8 @@ int main(int argc, char **argv) {
// Create a PassManager to hold and optimize the collection of passes we are
// about to build.
- //
- legacy::PassManager Passes;
+ OptCustomPassManager Passes;
+ bool AddOneTimeDebugifyPasses = EnableDebugify && !DebugifyEach;
// Add an appropriate TargetLibraryInfo pass for the module's triple.
TargetLibraryInfoImpl TLII(ModuleTriple);
@@ -571,8 +607,8 @@ int main(int argc, char **argv) {
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
- if (EnableDebugify)
- Passes.add(createDebugifyPass());
+ if (AddOneTimeDebugifyPasses)
+ Passes.add(createDebugifyModulePass());
std::unique_ptr<legacy::FunctionPassManager> FPasses;
if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz ||
@@ -719,8 +755,8 @@ int main(int argc, char **argv) {
if (!NoVerify && !VerifyEach)
Passes.add(createVerifierPass());
- if (EnableDebugify)
- Passes.add(createCheckDebugifyPass());
+ 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
OpenPOWER on IntegriCloud