diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/IR/IRPrintingPasses.h | 4 | ||||
| -rw-r--r-- | llvm/lib/IR/IRPrintingPasses.cpp | 8 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/debugify-each.ll | 24 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/debugify.ll | 20 | ||||
| -rw-r--r-- | llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll | 2 | ||||
| -rw-r--r-- | llvm/tools/opt/Debugify.cpp | 164 | ||||
| -rw-r--r-- | llvm/tools/opt/PassPrinters.h | 6 | ||||
| -rw-r--r-- | llvm/tools/opt/opt.cpp | 48 | 
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  | 

