Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -507,6 +507,9 @@ def arcmt_migrate : Flag<["-"], "arcmt-migrate">, HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def opt_record_file : Separate<["-"], "opt-record-file">, + HelpText<"File name to use for YAML optimization record output">; + def print_stats : Flag<["-"], "print-stats">, HelpText<"Print performance metrics and statistics">; def stats_file : Joined<["-"], "stats-file=">, Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1189,6 +1189,15 @@ Group; def foperator_arrow_depth_EQ : Joined<["-"], "foperator-arrow-depth=">, Group; + +def fsave_optimization_record : Flag<["-"], "fsave-optimization-record">, + Group, HelpText<"Generate a YAML optimization record file">; +def fno_save_optimization_record : Flag<["-"], "fno-save-optimization-record">, + Group, Flags<[NoArgumentUnused]>; +def fsave_optimization_record_EQ : Joined<["-"], "fsave-optimization-record=">, + Group, + HelpText<"Generate a YAML optimization record file with the specified name">; + def ftest_coverage : Flag<["-"], "ftest-coverage">, Group; def fvectorize : Flag<["-"], "fvectorize">, Group, HelpText<"Enable the loop vectorization passes">; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -181,6 +181,10 @@ /// object file. std::vector CudaGpuBinaryFileNames; + /// The name of the file to which the backend should save YAML optimization + /// records. + std::string OptRecordFile; + /// Regular expression to select optimizations for which we should enable /// optimization remarks. Transformation passes whose name matches this /// expression (and support this feature), will emit a diagnostic Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -33,6 +33,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/YAMLTraits.h" #include using namespace clang; using namespace llvm; @@ -181,6 +183,21 @@ Ctx.setDiagnosticHandler(DiagnosticHandler, this); Ctx.setDiagnosticHotnessRequested(CodeGenOpts.DiagnosticsWithHotness); + std::unique_ptr OptRecordFile; + if (!CodeGenOpts.OptRecordFile.empty()) { + std::error_code EC; + OptRecordFile = + llvm::make_unique(CodeGenOpts.OptRecordFile, + EC, sys::fs::F_None); + if (EC) { + Diags.Report(diag::err_cannot_open_file) << + CodeGenOpts.OptRecordFile << EC.message(); + return; + } + + Ctx.setDiagnosticsOutputFile(new yaml::Output(OptRecordFile->os())); + } + // Link LinkModule into this module if present, preserving its validity. for (auto &I : LinkModules) { unsigned LinkFlags = I.first; @@ -198,6 +215,9 @@ Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); Ctx.setDiagnosticHandler(OldDiagnosticHandler, OldDiagnosticContext); + + if (OptRecordFile) + OptRecordFile->keep(); } void HandleTagDeclDefinition(TagDecl *D) override { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3336,23 +3336,29 @@ } } -static const char *SplitDebugName(const ArgList &Args, const InputInfo &Input) { +static const char *getAltExtOutputName(const ArgList &Args, + const InputInfo &Input, + const char *Ext) { Arg *FinalOutput = Args.getLastArg(options::OPT_o); if (FinalOutput && Args.hasArg(options::OPT_c)) { SmallString<128> T(FinalOutput->getValue()); - llvm::sys::path::replace_extension(T, "dwo"); + llvm::sys::path::replace_extension(T, Ext); return Args.MakeArgString(T); } else { // Use the compilation dir. SmallString<128> T( Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); - llvm::sys::path::replace_extension(F, "dwo"); + llvm::sys::path::replace_extension(F, Ext); T += F; return Args.MakeArgString(F); } } +static const char *SplitDebugName(const ArgList &Args, const InputInfo &Input) { + return getAltExtOutputName(Args, Input, "dwo"); +} + static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const ArgList &Args, const InputInfo &Output, const char *OutFile) { @@ -3377,6 +3383,10 @@ C.addCommand(llvm::make_unique(JA, T, Exec, StripArgs, II)); } +static const char *getOptRecordName(const ArgList &Args, const InputInfo &Input) { + return getAltExtOutputName(Args, Input, "yaml"); +} + /// \brief Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { @@ -6068,6 +6078,18 @@ CmdArgs.push_back("-fno-math-builtin"); } + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fsave_optimization_record_EQ, + options::OPT_fno_save_optimization_record, false)) { + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ); + if (A) + CmdArgs.push_back(A->getValue()); + else + CmdArgs.push_back(getOptRecordName(Args, Input)); + } + // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: Now that PR4941 has been fixed this can be enabled. Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -823,6 +823,10 @@ Opts.LinkerOptions = Args.getAllArgValues(OPT_linker_option); bool NeedLocTracking = false; + Opts.OptRecordFile = Args.getLastArgValue(OPT_opt_record_file); + if (!Opts.OptRecordFile.empty()) + NeedLocTracking = true; + if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) { Opts.OptimizationRemarkPattern = GenerateOptimizationRemarkRegex(Diags, Args, A); Index: test/CodeGen/opt-record.c =================================================================== --- /dev/null +++ test/CodeGen/opt-record.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 %s -o %t -dwarf-column-info -opt-record-file %t.yaml -emit-obj +// RUN: cat %t.yaml | FileCheck %s +// REQUIRES: x86-registered-target + +void bar(); +void foo() { bar(); } + +void Test(int *res, int *c, int *d, int *p, int n) { + int i; + +#pragma clang loop vectorize(assume_safety) + for (i = 0; i < 1600; i++) { + res[i] = (p[i] == 0) ? res[i] : res[i] + d[i]; + } +} + +// CHECK: --- !Missed +// CHECK: Pass: inline +// CHECK: Name: NoDefinition +// CHECK: Function: foo + +// CHECK: --- !Passed +// CHECK: Pass: loop-vectorize +// CHECK: Name: Vectorized +// CHECK: Function: Test + Index: test/Driver/opt-record.c =================================================================== --- /dev/null +++ test/Driver/opt-record.c @@ -0,0 +1,9 @@ +// RUN: %clang -### -S -o FOO -fsave-optimization-record %s 2>&1 | FileCheck %s +// RUN: %clang -### -S -o FOO -fsave-optimization-record=BAR.txt %s 2>&1 | FileCheck %s -check-prefix=CHECK-EQ + +// CHECK: "-cc1" +// CHECK: "-opt-record-file" "opt-record.yaml" + +// CHECK-EQ: "-cc1" +// CHECK-EQ: "-opt-record-file" "BAR.txt" +