Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -157,6 +157,13 @@ HelpText<"Disable implicit builtin knowledge of math functions">; } +def middle_end_passes_EQ + : Joined<[ "-" ], "middle-end-passes=">, + HelpText<"Override the middle-end passes that are run">; +def middle_end_aa_pipeline_EQ + : Joined<[ "-" ], "middle-end-aa-pipeline=">, + HelpText<"Alias analysis pipeline to use with -middle-end-passes=">; + def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">, HelpText<"Don't run LLVM optimization passes">; def disable_llvm_verifier : Flag<["-"], "disable-llvm-verifier">, Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -107,6 +107,24 @@ /// Enable additional debugging information. std::string DebugPass; + /// Pass description string to override the middle-end pass pipeline. + /// This is primarily for developers experimenting with different + /// optimization pipelines. + /// This will completely replace the middle-end pass pipeline, so + /// features that depend on changes to the pipeline (e.g. sanitizers) may + /// not work as expected in conjunction with this option. + /// The string has the same format as the string passed to opt's + /// `-passes=` flag. + std::string MiddleEndPasses; + + /// Alias analysis description string to use with MiddleEndPasses. + /// This is primarily for developers experimenting with different + /// optimization pipelines. + /// This option only affects passes run by MiddleEndPasses. + /// The string has the same format as the string passed to opt's + /// `-aa-pipeline=` flag. + std::string MiddleEndAAPipeline; + /// The string to embed in debug information as the current working directory. std::string DebugCompilationDir; Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/ModuleSummaryIndexObjectFile.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/TargetRegistry.h" @@ -643,6 +644,43 @@ return true; } +static void runMiddleEndPasses(Module &M, TargetMachine *TM, StringRef Passes, + StringRef AAPipeline) { + // This is a really low-level internal developer option. + // Use report_fatal_error if anything goes wrong. + + PassBuilder PB(TM); + AAManager AA; + if (!PB.parseAAPipeline(AA, AAPipeline)) + report_fatal_error("Unable to parse AA pipeline description: " + + AAPipeline); + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + // Register the AA manager first so that our version is the one used. + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + MPM.addPass(VerifierPass()); + + // Now, add all the passes we've been requested to. + if (!PB.parsePassPipeline(MPM, Passes)) + report_fatal_error("Unable to parse pass pipeline description: " + Passes); + + MPM.addPass(VerifierPass()); + MPM.run(M, MAM); +} + void EmitAssemblyHelper::EmitAssembly(BackendAction Action, std::unique_ptr OS) { TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr); @@ -687,7 +725,11 @@ PerFunctionPasses.add( createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); - CreatePasses(PerModulePasses, PerFunctionPasses, ModuleSummary.get()); + bool UseCustomMiddleEndPasses = !CodeGenOpts.MiddleEndPasses.empty(); + // If we are going to use a custom middle-end pass pipeline, don't add + // any of the usual passes. + if (!UseCustomMiddleEndPasses) + CreatePasses(PerModulePasses, PerFunctionPasses, ModuleSummary.get()); legacy::PassManager CodeGenPasses; CodeGenPasses.add( @@ -716,6 +758,18 @@ // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); + if (UseCustomMiddleEndPasses) { + // Override the middle-end pass pipeline. + // Note that we still run the old PM managers later because they + // contain e.g. the passes for printing out a BC or LL file (e.g. for + // -flto). + // But these passes don't affect the actual optimization because there + // is nothing else run in the old PM except for the printing passes. + + runMiddleEndPasses(*TheModule, TM.get(), CodeGenOpts.MiddleEndPasses, + CodeGenOpts.MiddleEndAAPipeline); + } + // Run passes. For now we do all passes at once, but eventually we // would like to have the option of streaming code generation. Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -12,6 +12,7 @@ MC ObjCARCOpts Object + Passes ProfileData ScalarOpts Support Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -845,6 +845,11 @@ Opts.EmitCheckPathComponentsToStrip = getLastArgIntValue( Args, OPT_fsanitize_undefined_strip_path_components_EQ, 0, Diags); + if (Arg *A = Args.getLastArg(OPT_middle_end_passes_EQ)) + Opts.MiddleEndPasses = A->getValue(); + if (Arg *A = Args.getLastArg(OPT_middle_end_aa_pipeline_EQ)) + Opts.MiddleEndAAPipeline = A->getValue(); + return Success; } Index: test/CodeGen/middle-end-passes.c =================================================================== --- /dev/null +++ test/CodeGen/middle-end-passes.c @@ -0,0 +1,26 @@ +// Check that passes get run. + +// RUN: %clang_cc1 %s -emit-llvm -o /dev/null -middle-end-passes=mem2reg,aa-eval 2>&1 | FileCheck %s --check-prefix=NO-AA + +// NO-AA: ===== Alias Analysis Evaluator Report ===== +// NO-AA: 0 must alias responses + +// RUN: %clang_cc1 %s -emit-llvm -o /dev/null -middle-end-passes=mem2reg,aa-eval -middle-end-aa-pipeline=basic-aa 2>&1 | FileCheck %s --check-prefix=WITH-AA + +// WITH-AA: ===== Alias Analysis Evaluator Report ===== +// WITH-AA: 1 must alias responses + + +// The actual output with -flto or -emit-llvm is generated by running a +// pass in the old PM. Verify that that we still get output. + +// RUN: %clang -flto -c %s -o - -Xclang -middle-end-passes=mem2reg 2>&1 | opt -S | FileCheck %s --check-prefix=OUTPUT-IS-GENERATED +// RUN: %clang -emit-llvm -S %s -o - -Xclang -middle-end-passes=mem2reg 2>&1 | FileCheck %s --check-prefix=OUTPUT-IS-GENERATED + +// OUTPUT-IS-GENERATED: @foo + +int foo(int *x) { + int *y = x + 1; + int *z = y - 1; + return *x + *z; +}