Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -171,6 +171,9 @@ /// The ABI to use for passing floating point arguments. std::string FloatABI; + /// The file to use for dumping bug report by `debugify` in `original` mode. + std::string DIOriginalBugsReportFilePath; + /// The floating-point denormal mode to use. llvm::DenormalMode FPDenormalMode = llvm::DenormalMode::getIEEE(); Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -65,6 +65,10 @@ CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled. CODEGENOPT(EmitCallSiteInfo, 1, 0) ///< Emit call site info only in the case of ///< '-g' + 'O>0' level. +CODEGENOPT(EnableDebugifyEachOriginal, 1, 0) ///< Enable debugify each in + ///< original mode (it means check + ///< the original debug info + ///< metadata preservation). CODEGENOPT(IndirectTlsSegRefs, 1, 0) ///< Set when -mno-tls-direct-seg-refs ///< is specified. CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls. Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -389,6 +389,16 @@ HelpText<"Prints debug information for the new pass manager">; def fno_debug_pass_manager : Flag<["-"], "fno-debug-pass-manager">, HelpText<"Disables debug printing for the new pass manager">; +def fenable_debugify_each_original + : Flag<["-"], "fenable-debugify-each-original">, + HelpText<"Enable Debug Info Metadata preservation testing in " + "optimizations.">; +def fenable_debugify_original_export + : Joined<["-"], "fenable-debugify-original-export=">, + MetaVarName<"">, + HelpText<"Export debugify (by testing original Debug Info) failures into " + "specified (JSON) file (should be abs path as we use " + "append mode to insert new JSON objects).">; // The driver option takes the key as a parameter to the -msign-return-address= // and -mbranch-protection= options, but CC1 has a separate option so we // don't have to parse the parameter twice. Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -76,6 +76,7 @@ #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" +#include "llvm/Transforms/Utils/Debugify.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" #include "llvm/Transforms/Utils/SymbolRewriter.h" @@ -851,6 +852,67 @@ return true; } +class ClangCustomPassManager : public legacy::PassManager { +public: + void add(Pass *P) override { + bool WrapWithDebugifyOriginal = DebugifyEachOriginalEnabled && + !P->getAsImmutablePass() && + !isIRPrintingPass(P); + if (!WrapWithDebugifyOriginal) { + PassManager::add(P); + return; + } + + PassKind Kind = P->getPassKind(); + StringRef Name = P->getPassName(); + + // TODO: Implement Debugify for LoopPass. + switch (Kind) { + case PT_Function: + assert(Mode == DebugifyMode::OriginalDebugInfo && + "Must be original mode"); + PassManager::add(createDebugifyFunctionPass(DebugifyMode::OriginalDebugInfo, + Name, &DIPreservationMap)); + PassManager::add(P); + PassManager::add(createCheckDebugifyFunctionPass( + false, Name, nullptr, DebugifyMode::OriginalDebugInfo, + &DIPreservationMap, getDebugifyEachOriginalPath())); + break; + case PT_Module: + assert(Mode == DebugifyMode::OriginalDebugInfo && + "Must be original mode"); + PassManager::add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, + Name, &DIPreservationMap)); + PassManager::add(P); + PassManager::add(createCheckDebugifyModulePass( + false, Name, nullptr, DebugifyMode::OriginalDebugInfo, + &DIPreservationMap, getDebugifyEachOriginalPath())); + break; + default: + PassManager::add(P); + break; + } + } + + void enableDebugifyEachOriginal() { + DebugifyEachOriginalEnabled = true; + } + + void setDIOriginalBugsReportFilePath( + StringRef DIOriginalBugsReportFilePath_) { + DIOriginalBugsReportFilePath = DIOriginalBugsReportFilePath_; + } + + llvm::StringRef getDebugifyEachOriginalPath() const { + return DIOriginalBugsReportFilePath; + } + +private: + DebugInfoPerPassMap DIPreservationMap; + llvm::StringRef DIOriginalBugsReportFilePath = ""; + bool DebugifyEachOriginalEnabled = false; +}; + void EmitAssemblyHelper::EmitAssembly(BackendAction Action, std::unique_ptr OS) { TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr); @@ -867,7 +929,14 @@ if (TM) TheModule->setDataLayout(TM->createDataLayout()); - legacy::PassManager PerModulePasses; + ClangCustomPassManager PerModulePasses; + if (CodeGenOpts.EnableDebugifyEachOriginal) { + PerModulePasses.enableDebugifyEachOriginal(); + + if (!CodeGenOpts.DIOriginalBugsReportFilePath.empty()) + PerModulePasses.setDIOriginalBugsReportFilePath( + CodeGenOpts.DIOriginalBugsReportFilePath); + } PerModulePasses.add( createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -791,6 +791,16 @@ llvm::is_contained(DebugEntryValueArchs, T.getArch())) Opts.EmitCallSiteInfo = true; + Opts.EnableDebugifyEachOriginal = + Args.hasArg(OPT_fenable_debugify_each_original); + // Ignore the option if the -fenable-debugify-each-original wasn't enabled. + if (Opts.EnableDebugifyEachOriginal && + Args.hasArg(OPT_fenable_debugify_original_export)) { + Opts.DIOriginalBugsReportFilePath = + std::string( + Args.getLastArgValue(OPT_fenable_debugify_original_export)); + } + Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.IndirectTlsSegRefs = Args.hasArg(OPT_mno_tls_direct_seg_refs); Index: clang/test/DebugInfo/debugify-each-original.c =================================================================== --- /dev/null +++ clang/test/DebugInfo/debugify-each-original.c @@ -0,0 +1,61 @@ +// Ensure that we tested each pass with the feature, but we do not +// check the final result here. It is up to LLVM test suite to check the real +// logic of the functionality. + +// RUN: %clang -g -Xclang -fenable-debugify-each-original -emit-llvm -S \ +// RUN: -O1 -o - %s 2>&1 | FileCheck %s + +int main() +{ + int x = 1; + int y = 2; + return x + y; +} + +// CHECK: Force set function attributes: {{.*}} +// CHECK-NEXT: Infer set function attributes: {{.*}} +// CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation: {{.*}} +// CHECK-NEXT: Called Value Propagation: {{.*}} +// CHECK-NEXT: Global Variable Optimizer: {{.*}} +// CHECK-NEXT: Promote Memory to Register: {{.*}} +// CHECK-NEXT: Dead Argument Elimination: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Globals Alias Analysis: {{.*}} +// CHECK-NEXT: SROA: {{.*}} +// CHECK-NEXT: Early CSE w/ MemorySSA: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: Conditionally eliminate dead library calls: {{.*}} +// CHECK-NEXT: PGOMemOPSize: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Reassociate expressions: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: MemCpy Optimization: {{.*}} +// CHECK-NEXT: Sparse Conditional Constant Propagation: {{.*}} +// CHECK-NEXT: Bit-Tracking Dead Code Elimination: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: Aggressive Dead Code Elimination: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: A No-Op Barrier {{.*}}: {{.*}} +// CHECK-NEXT: Deduce function attributes in RPO: {{.*}} +// CHECK-NEXT: Global Variable Optimizer: {{.*}} +// CHECK-NEXT: Dead Global Elimination: {{.*}} +// CHECK-NEXT: Globals Alias Analysis: {{.*}} +// CHECK-NEXT: Float to int: {{.*}} +// CHECK-NEXT: Lower constant intrinsics: {{.*}} +// CHECK-NEXT: Loop Distribution: {{.*}} +// CHECK-NEXT: Loop Vectorization: {{.*}} +// CHECK-NEXT: Loop Load Elimination: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} +// CHECK-NEXT: Optimize scalar/vector ops: {{.*}} +// CHECK-NEXT: Combine redundant instructions: {{.*}} +// CHECK-NEXT: Warn about non-applied transformations: {{.*}} +// CHECK-NEXT: Alignment from assumptions: {{.*}} +// CHECK-NEXT: Strip Unused Function Prototypes: {{.*}} +// CHECK-NEXT: Remove redundant instructions: {{.*}} +// CHECK-NEXT: Hoist/decompose integer division and remainder: {{.*}} +// CHECK-NEXT: Simplify the CFG: {{.*}} Index: llvm/docs/HowToUpdateDebugInfo.rst =================================================================== --- llvm/docs/HowToUpdateDebugInfo.rst +++ llvm/docs/HowToUpdateDebugInfo.rst @@ -317,6 +317,16 @@ $ llvm-debugify-original.py sample.json sample.html +The `original` mode can be invoked from front-end level as follows: + +.. code-block:: bash + + # Test each pass. + $ clang -Xclang -fenable-debugify-each-original -g -O2 sample.c + + # Test each pass and export the issues report into the JSON file. + $ clang -Xclang -fenable-debugify-each-original -Xclang -fenable-debugify-original-export=sample.json -g -O2 sample.c + Using ``debugify`` ^^^^^^^^^^^^^^^^^^