diff options
Diffstat (limited to 'tools/opt')
| -rw-r--r-- | tools/opt/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | tools/opt/Debugify.cpp | 212 | ||||
| -rw-r--r-- | tools/opt/NewPMDriver.cpp | 55 | ||||
| -rw-r--r-- | tools/opt/NewPMDriver.h | 8 | ||||
| -rw-r--r-- | tools/opt/PassPrinters.cpp | 9 | ||||
| -rw-r--r-- | tools/opt/PassPrinters.h | 8 | ||||
| -rw-r--r-- | tools/opt/opt.cpp | 43 |
7 files changed, 307 insertions, 31 deletions
diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index 518396e36028..dedc25143cf4 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -25,6 +25,7 @@ set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(opt AnalysisWrappers.cpp BreakpointPrinter.cpp + Debugify.cpp GraphPrinters.cpp NewPMDriver.cpp PassPrinters.cpp @@ -37,5 +38,5 @@ add_llvm_tool(opt export_executable_symbols(opt) if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) - target_link_libraries(opt Polly) + target_link_libraries(opt PRIVATE Polly) endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) diff --git a/tools/opt/Debugify.cpp b/tools/opt/Debugify.cpp new file mode 100644 index 000000000000..40ee545c098d --- /dev/null +++ b/tools/opt/Debugify.cpp @@ -0,0 +1,212 @@ +//===- Debugify.cpp - Attach synthetic debug info to everything -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file This pass attaches synthetic debug info to everything. It can be used +/// to create targeted tests for debug info preservation. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO.h" + +using namespace llvm; + +namespace { + +bool applyDebugifyMetadata(Module &M) { + // Skip modules with debug info. + if (M.getNamedMetadata("llvm.dbg.cu")) { + errs() << "Debugify: Skipping module with debug info\n"; + return false; + } + + DIBuilder DIB(M); + LLVMContext &Ctx = M.getContext(); + + // Get a DIType which corresponds to Ty. + DenseMap<uint64_t, DIType *> TypeCache; + auto getCachedDIType = [&](Type *Ty) -> DIType * { + uint64_t Size = M.getDataLayout().getTypeAllocSizeInBits(Ty); + DIType *&DTy = TypeCache[Size]; + if (!DTy) { + std::string Name = "ty" + utostr(Size); + DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); + } + return DTy; + }; + + unsigned NextLine = 1; + unsigned NextVar = 1; + auto File = DIB.createFile(M.getName(), "/"); + auto CU = + DIB.createCompileUnit(dwarf::DW_LANG_C, DIB.createFile(M.getName(), "/"), + "debugify", /*isOptimized=*/true, "", 0); + + // Visit each instruction. + for (Function &F : M) { + if (F.isDeclaration()) + continue; + + auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); + bool IsLocalToUnit = F.hasPrivateLinkage() || F.hasInternalLinkage(); + auto SP = + DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, SPType, + IsLocalToUnit, F.hasExactDefinition(), NextLine, + DINode::FlagZero, /*isOptimized=*/true); + F.setSubprogram(SP); + for (BasicBlock &BB : F) { + // Attach debug locations. + for (Instruction &I : BB) + I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + + // Attach debug values. + for (Instruction &I : BB) { + // Skip void-valued instructions. + if (I.getType()->isVoidTy()) + continue; + + // Skip the terminator instruction and any just-inserted intrinsics. + if (isa<TerminatorInst>(&I) || isa<DbgValueInst>(&I)) + break; + + std::string Name = utostr(NextVar++); + const DILocation *Loc = I.getDebugLoc().get(); + auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), + getCachedDIType(I.getType()), + /*AlwaysPreserve=*/true); + DIB.insertDbgValueIntrinsic(&I, LocalVar, DIB.createExpression(), Loc, + BB.getTerminator()); + } + } + DIB.finalizeSubprogram(SP); + } + DIB.finalize(); + + // Track the number of distinct lines and variables. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); + auto *IntTy = Type::getInt32Ty(Ctx); + auto addDebugifyOperand = [&](unsigned N) { + NMD->addOperand(MDNode::get( + Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N)))); + }; + addDebugifyOperand(NextLine - 1); // Original number of lines. + addDebugifyOperand(NextVar - 1); // Original number of variables. + return true; +} + +void checkDebugifyMetadata(Module &M) { + // Skip modules without debugify metadata. + NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); + if (!NMD) + return; + + auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { + return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) + ->getZExtValue(); + }; + unsigned OriginalNumLines = getDebugifyOperand(0); + unsigned OriginalNumVars = getDebugifyOperand(1); + bool HasErrors = false; + + // Find missing lines. + BitVector MissingLines{OriginalNumLines, true}; + for (Function &F : M) { + for (Instruction &I : instructions(F)) { + if (isa<DbgValueInst>(&I)) + continue; + + auto DL = I.getDebugLoc(); + if (DL) { + MissingLines.reset(DL.getLine() - 1); + continue; + } + + outs() << "ERROR: Instruction with empty DebugLoc -- "; + 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) { + for (Instruction &I : instructions(F)) { + auto *DVI = dyn_cast<DbgValueInst>(&I); + if (!DVI) + continue; + + unsigned Var = ~0U; + (void)to_integer(DVI->getVariable()->getName(), Var, 10); + assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); + MissingVars.reset(Var - 1); + } + } + for (unsigned Idx : MissingVars.set_bits()) + outs() << "ERROR: Missing variable " << Idx + 1 << "\n"; + HasErrors |= MissingVars.count() > 0; + + outs() << "CheckDebugify: " << (HasErrors ? "FAIL" : "PASS") << "\n"; +} + +/// Attach synthetic debug info to everything. +struct DebugifyPass : public ModulePass { + bool runOnModule(Module &M) override { return applyDebugifyMetadata(M); } + + DebugifyPass() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + static char ID; // Pass identification. +}; + +/// Check debug info inserted by -debugify for completeness. +struct CheckDebugifyPass : public ModulePass { + bool runOnModule(Module &M) override { + checkDebugifyMetadata(M); + return false; + } + + CheckDebugifyPass() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + static char ID; // Pass identification. +}; + +} // end anonymous namespace + +char DebugifyPass::ID = 0; +static RegisterPass<DebugifyPass> X("debugify", + "Attach debug info to everything"); + +char CheckDebugifyPass::ID = 0; +static RegisterPass<CheckDebugifyPass> Y("check-debugify", + "Check debug info from -debugify"); diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp index 94242d795aae..a3f16f2538c4 100644 --- a/tools/opt/NewPMDriver.cpp +++ b/tools/opt/NewPMDriver.cpp @@ -18,6 +18,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/Config/config.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" @@ -81,6 +82,22 @@ static cl::opt<std::string> VectorizerStartEPPipeline( cl::desc("A textual description of the function pass pipeline inserted at " "the VectorizerStart extension point into default pipelines"), cl::Hidden); +enum PGOKind { NoPGO, InstrGen, InstrUse, SampleUse }; +static cl::opt<PGOKind> PGOKindFlag( + "pgo-kind", cl::init(NoPGO), cl::Hidden, + cl::desc("The kind of profile guided optimization"), + cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."), + clEnumValN(InstrGen, "new-pm-pgo-instr-gen-pipeline", + "Instrument the IR to generate profile."), + clEnumValN(InstrUse, "new-pm-pgo-instr-use-pipeline", + "Use instrumented profile to guide PGO."), + clEnumValN(SampleUse, "new-pm-pgo-sample-use-pipeline", + "Use sampled profile to guide PGO."))); +static cl::opt<std::string> ProfileFile( + "profile-file", cl::desc("Path to the profile."), cl::Hidden); +static cl::opt<bool> DebugInfoForProfiling( + "new-pm-debug-info-for-profiling", cl::init(false), cl::Hidden, + cl::desc("Emit special debug info to enable PGO profile generation.")); /// @}} template <typename PassManagerT> @@ -144,18 +161,46 @@ static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass, }); } +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void RegisterPollyPasses(PassBuilder &); +} +#endif + bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, - tool_output_file *Out, - tool_output_file *ThinLTOLinkOut, + ToolOutputFile *Out, ToolOutputFile *ThinLTOLinkOut, + ToolOutputFile *OptRemarkFile, StringRef PassPipeline, OutputKind OK, VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash) { bool VerifyEachPass = VK == VK_VerifyEachPass; - PassBuilder PB(TM); + + Optional<PGOOptions> P; + switch (PGOKindFlag) { + case InstrGen: + P = PGOOptions(ProfileFile, "", "", true); + break; + case InstrUse: + P = PGOOptions("", ProfileFile, "", false); + break; + case SampleUse: + P = PGOOptions("", "", ProfileFile, false); + break; + case NoPGO: + if (DebugInfoForProfiling) + P = PGOOptions("", "", "", false, true); + else + P = None; + } + PassBuilder PB(TM, P); registerEPCallbacks(PB, VerifyEachPass, DebugPM); +#ifdef LINK_POLLY_INTO_TOOLS + polly::RegisterPollyPasses(PB); +#endif + // Specially handle the alias analysis manager so that we can register // a custom pipeline of AA passes with it. AAManager AA; @@ -221,5 +266,9 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, if (OK == OK_OutputThinLTOBitcode && ThinLTOLinkOut) ThinLTOLinkOut->keep(); } + + if (OptRemarkFile) + OptRemarkFile->keep(); + return true; } diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h index 8012e0a025c9..e5490deaeaf5 100644 --- a/tools/opt/NewPMDriver.h +++ b/tools/opt/NewPMDriver.h @@ -26,7 +26,7 @@ class StringRef; class LLVMContext; class Module; class TargetMachine; -class tool_output_file; +class ToolOutputFile; namespace opt_tool { enum OutputKind { @@ -52,9 +52,9 @@ enum VerifierKind { /// ThinLTOLinkOut is only used when OK is OK_OutputThinLTOBitcode, and can be /// nullptr. bool runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, - tool_output_file *Out, tool_output_file *ThinLinkOut, - StringRef PassPipeline, opt_tool::OutputKind OK, - opt_tool::VerifierKind VK, + ToolOutputFile *Out, ToolOutputFile *ThinLinkOut, + ToolOutputFile *OptRemarkFile, StringRef PassPipeline, + opt_tool::OutputKind OK, opt_tool::VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash); diff --git a/tools/opt/PassPrinters.cpp b/tools/opt/PassPrinters.cpp index 65a53038fc50..f52b52080949 100644 --- a/tools/opt/PassPrinters.cpp +++ b/tools/opt/PassPrinters.cpp @@ -11,12 +11,18 @@ /// \brief Utilities to print analysis info for various kinds of passes. /// //===----------------------------------------------------------------------===// + #include "PassPrinters.h" +#include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/RegionInfo.h" #include "llvm/Analysis/RegionPass.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Function.h" #include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" #include <string> using namespace llvm; @@ -226,7 +232,8 @@ struct BasicBlockPassPrinter : public BasicBlockPass { }; char BasicBlockPassPrinter::ID = 0; -} + +} // end anonymous namespace FunctionPass *llvm::createFunctionPassPrinter(const PassInfo *PI, raw_ostream &OS, bool Quiet) { diff --git a/tools/opt/PassPrinters.h b/tools/opt/PassPrinters.h index cf46ef9e36d2..14b6e43d18e0 100644 --- a/tools/opt/PassPrinters.h +++ b/tools/opt/PassPrinters.h @@ -1,4 +1,4 @@ -//===- PassPrinters.h - Utilities to print analysis info for passes -------===// +//=- PassPrinters.h - Utilities to print analysis info for passes -*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -11,6 +11,7 @@ /// \brief Utilities to print analysis info for various kinds of passes. /// //===----------------------------------------------------------------------===// + #ifndef LLVM_TOOLS_OPT_PASSPRINTERS_H #define LLVM_TOOLS_OPT_PASSPRINTERS_H @@ -22,8 +23,8 @@ class FunctionPass; class ModulePass; class LoopPass; class PassInfo; -class RegionPass; class raw_ostream; +class RegionPass; FunctionPass *createFunctionPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet); @@ -42,6 +43,7 @@ RegionPass *createRegionPassPrinter(const PassInfo *PI, raw_ostream &out, BasicBlockPass *createBasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet); -} + +} // end namespace llvm #endif // LLVM_TOOLS_OPT_PASSPRINTERS_H diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 24cce58047f1..5bc00ea35ae5 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -23,7 +23,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" -#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/CommandFlags.def" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" @@ -349,7 +349,7 @@ static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr, return TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr, Options, getRelocModel(), - CMModel, GetCodeGenOptLevel()); + getCodeModel(), GetCodeGenOptLevel()); } #ifdef LINK_POLLY_INTO_TOOLS @@ -391,6 +391,7 @@ int main(int argc, char **argv) { initializeTarget(Registry); // For codegen passes, only passes that do IR to IR transformation are // supported. + initializeExpandMemCmpPassPass(Registry); initializeScalarizeMaskedMemIntrinPass(Registry); initializeCodeGenPreparePass(Registry); initializeAtomicExpandPass(Registry); @@ -402,9 +403,11 @@ int main(int argc, char **argv) { initializePreISelIntrinsicLoweringLegacyPassPass(Registry); initializeGlobalMergePass(Registry); initializeInterleavedAccessPass(Registry); - initializeCountingFunctionInserterPass(Registry); + initializeEntryExitInstrumenterPass(Registry); + initializePostInlineEntryExitInstrumenterPass(Registry); initializeUnreachableBlockElimLegacyPassPass(Registry); initializeExpandReductionsPass(Registry); + initializeWriteBitcodePassPass(Registry); #ifdef LINK_POLLY_INTO_TOOLS polly::initializePollyPasses(Registry); @@ -430,21 +433,22 @@ int main(int argc, char **argv) { if (PassRemarksHotnessThreshold) Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold); - std::unique_ptr<tool_output_file> YamlFile; + std::unique_ptr<ToolOutputFile> OptRemarkFile; if (RemarksFilename != "") { std::error_code EC; - YamlFile = llvm::make_unique<tool_output_file>(RemarksFilename, EC, - sys::fs::F_None); + OptRemarkFile = + llvm::make_unique<ToolOutputFile>(RemarksFilename, EC, sys::fs::F_None); if (EC) { errs() << EC.message() << '\n'; return 1; } Context.setDiagnosticsOutputFile( - llvm::make_unique<yaml::Output>(YamlFile->os())); + llvm::make_unique<yaml::Output>(OptRemarkFile->os())); } // Load the input module... - std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context); + std::unique_ptr<Module> M = + parseIRFile(InputFilename, Err, Context, !NoVerify); if (!M) { Err.print(argv[0], errs()); @@ -471,8 +475,8 @@ int main(int argc, char **argv) { M->setDataLayout(ClDataLayout); // Figure out what stream we are supposed to write to... - std::unique_ptr<tool_output_file> Out; - std::unique_ptr<tool_output_file> ThinLinkOut; + std::unique_ptr<ToolOutputFile> Out; + std::unique_ptr<ToolOutputFile> ThinLinkOut; if (NoOutput) { if (!OutputFilename.empty()) errs() << "WARNING: The -o (output filename) option is ignored when\n" @@ -483,7 +487,7 @@ int main(int argc, char **argv) { OutputFilename = "-"; std::error_code EC; - Out.reset(new tool_output_file(OutputFilename, EC, sys::fs::F_None)); + Out.reset(new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; return 1; @@ -491,7 +495,7 @@ int main(int argc, char **argv) { if (!ThinLinkBitcodeFile.empty()) { ThinLinkOut.reset( - new tool_output_file(ThinLinkBitcodeFile, EC, sys::fs::F_None)); + new ToolOutputFile(ThinLinkBitcodeFile, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; return 1; @@ -540,7 +544,8 @@ int main(int argc, char **argv) { // string. Hand off the rest of the functionality to the new code for that // layer. return runPassPipeline(argv[0], *M, TM.get(), Out.get(), ThinLinkOut.get(), - PassPipeline, OK, VK, PreserveAssemblyUseListOrder, + OptRemarkFile.get(), PassPipeline, OK, VK, + PreserveAssemblyUseListOrder, PreserveBitcodeUseListOrder, EmitSummaryIndex, EmitModuleHash) ? 0 @@ -579,8 +584,8 @@ int main(int argc, char **argv) { OutputFilename = "-"; std::error_code EC; - Out = llvm::make_unique<tool_output_file>(OutputFilename, EC, - sys::fs::F_None); + Out = llvm::make_unique<ToolOutputFile>(OutputFilename, EC, + sys::fs::F_None); if (EC) { errs() << EC.message() << '\n'; return 1; @@ -767,8 +772,8 @@ int main(int argc, char **argv) { "the compile-twice option\n"; Out->os() << BOS->str(); Out->keep(); - if (YamlFile) - YamlFile->keep(); + if (OptRemarkFile) + OptRemarkFile->keep(); return 1; } Out->os() << BOS->str(); @@ -778,8 +783,8 @@ int main(int argc, char **argv) { if (!NoOutput || PrintBreakpoints) Out->keep(); - if (YamlFile) - YamlFile->keep(); + if (OptRemarkFile) + OptRemarkFile->keep(); if (ThinLinkOut) ThinLinkOut->keep(); |
