diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -632,6 +632,11 @@ /// \return True if the argument combination will end up generating remarks. bool willEmitRemarks(const llvm::opt::ArgList &Args); +/// \return True if the argument combination will end up outputing remarks +/// onto screen. +/// This checks for clang specific R-value ('-Rpass-*') group. +bool hasRpassOptions(const llvm::opt::ArgList &Args); + } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -5214,3 +5214,19 @@ return true; return false; } + +bool clang::driver::hasRpassOptions(const ArgList &Args) { + // -Rpass= enables it. + if (Args.getLastArg(options::OPT_Rpass_EQ)) + return true; + + // -Rpass-missed= alone enables it too. + if (Args.getLastArg(options::OPT_Rpass_missed_EQ)) + return true; + + // -Rpass-analysis= alone enables it too. + if (Args.getLastArg(options::OPT_Rpass_analysis_EQ)) + return true; + + return false; +} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -60,6 +60,95 @@ using namespace clang; using namespace llvm::opt; +// Remarks option pass-through only happens when +// 1). single arch target +// 2). linker is lld +static bool checkRemarksOptions(StringRef LinkerPath, const ArgList &Args, + const llvm::Triple &Triple) { + bool hasMultipleArchs = + Triple.isOSDarwin() && Args.getAllArgValues(options::OPT_arch).size() > 1; + + bool isLLD = llvm::sys::path::filename(LinkerPath) == "ld.lld" || + llvm::sys::path::stem(LinkerPath) != "ld.lld"; + if (hasMultipleArchs || !isLLD) + return false; + return true; +} + +static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) { + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = std::string("-pass-remarks=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } + + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = std::string("-pass-remarks-missed=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } + + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = std::string("-pass-remarks-analysis=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Input, + const InputInfo &Output) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("--opt-remarks-filename"); + + SmallString<128> F; + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + F = A->getValue(); + } else { + if (Output.isFilename()) + F = Output.getFilename(); + + if (F.empty()) { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + } + } + // Append "opt.ld." to the end of the file name. + SmallString<32> Extension; + Extension += ".opt.ld."; + Extension += Format; + + CmdArgs.push_back(Args.MakeArgString(F + Extension)); + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("--opt-remarks-passes"); + CmdArgs.push_back(A->getValue()); + } + + CmdArgs.push_back("--opt-remarks-format"); + CmdArgs.push_back(Format.data()); +} + +static void renderRemarksHotnessOptions(const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness, false)) + CmdArgs.push_back("--opt-remarks-with-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + std::string Opt = + std::string("--opt-remarks-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } +} + void tools::addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths) { if (D.getVFS().exists(Path)) @@ -531,6 +620,23 @@ Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true); + + if (checkRemarksOptions(Linker, Args, ToolChain.getEffectiveTriple())) { + // handle remark diagnostics on screen options: '-Rpass-*' + if (hasRpassOptions(Args)) { + renderRpassOptions(Args, CmdArgs); + } + + // handle serialized remarks options: '-fsave-optimization-record' + // and '-foptimization-record-*' + if (willEmitRemarks(Args)) { + renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input, + Output); + } + + // handle remarks hotness/threshold related options + renderRemarksHotnessOptions(Args, CmdArgs); + } } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, diff --git a/clang/test/Driver/remarks-pass-through.c b/clang/test/Driver/remarks-pass-through.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/remarks-pass-through.c @@ -0,0 +1,28 @@ +// This test verifies remarks options pass-through into linker(lld) + +// no pass-through if lto is disabled +// RUN: %clang -### -o FOO -fdiagnostics-hotness-threshold=100 -fsave-optimization-record %s 2>&1 | not FileCheck %s + +// no pass-through if linker is not lld +// RUN: %clang -### -o FOO -fuse-ld=gold -fdiagnostics-hotness-threshold=100 -fsave-optimization-record %s 2>&1 | not FileCheck %s + +// pass-through cases +// RUN: %clang -### -o FOO -fuse-ld=lld -flto -fdiagnostics-hotness-threshold=100 -fsave-optimization-record -foptimization-record-passes=inline %s 2>&1 | FileCheck %s + +// RUN: %clang -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -fsave-optimization-record=some-format -foptimization-record-file=FOO.txt %s 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM +// +// RUN: %clang -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -Rpass=inline -Rpass-missed=inline -Rpass-analysis=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-RPASS +// +// CHECK: "--opt-remarks-filename" "FOO.opt.ld.yaml" +// CHECK: "--opt-remarks-passes" "inline" +// CHECK: "--opt-remarks-format" "yaml" +// CHECK: "--opt-remarks-hotness-threshold=100" +// +// CHECK-CUSTOM: "--opt-remarks-filename" "FOO.txt.opt.ld.some-format" +// CHECK-CUSTOM: "--opt-remarks-format" "some-format" +// CHECK-CUSTOM: "--opt-remarks-hotness-threshold=100" +// +// CHECK-RPASS: "-mllvm" "-pass-remarks=inline" +// CHECK-RPASS: "-mllvm" "-pass-remarks-missed=inline" +// CHECK-RPASS: "-mllvm" "-pass-remarks-analysis=inline" +// CHECK-RPASS: "--opt-remarks-hotness-threshold=100"