From: Nick Lewycky Date: Wed, 31 Aug 2016 23:04:32 +0000 (+0000) Subject: Add -fprofile-dir= to clang. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1051c8cacaad120b28f2e5013c2e85da8e95b264;p=clang Add -fprofile-dir= to clang. -fprofile-dir=path allows the user to specify where .gcda files should be emitted when the program is run. In particular, this is the first flag that causes the .gcno and .o files to have different paths, LLVM is extended to support this. -fprofile-dir= does not change the file name in the .gcno (and thus where lcov looks for the source) but it does change the name in the .gcda (and thus where the runtime library writes the .gcda file). It's different from a GCOV_PREFIX because a user can observe that the GCOV_PREFIX_STRIP will strip paths off of -fprofile-dir= but not off of a supplied GCOV_PREFIX. To implement this we split -coverage-file into -coverage-data-file and -coverage-notes-file to specify the two different names. The !llvm.gcov metadata node grows from a 2-element form {string coverage-file, node dbg.cu} to 3-elements, {string coverage-notes-file, string coverage-data-file, node dbg.cu}. In the 3-element form, the file name is already "mangled" with .gcno/.gcda suffixes, while the 2-element form left that to the middle end pass. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@280306 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index bfe56f9d4b..cb22cdfd54 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -192,9 +192,14 @@ def femit_coverage_notes : Flag<["-"], "femit-coverage-notes">, HelpText<"Emit a gcov coverage notes file when compiling.">; def femit_coverage_data: Flag<["-"], "femit-coverage-data">, HelpText<"Instrument the program to emit gcov coverage data when run.">; -def coverage_file : Separate<["-"], "coverage-file">, - HelpText<"Emit coverage data to this filename. The extension will be replaced.">; -def coverage_file_EQ : Joined<["-"], "coverage-file=">, Alias; +def coverage_data_file : Separate<["-"], "coverage-data-file">, + HelpText<"Emit coverage data to this filename.">; +def coverage_data_file_EQ : Joined<["-"], "coverage-data-file=">, + Alias; +def coverage_notes_file : Separate<["-"], "coverage-notes-file">, + HelpText<"Emit coverage notes to this filename.">; +def coverage_notes_file_EQ : Joined<["-"], "coverage-notes-file=">, + Alias; def coverage_cfg_checksum : Flag<["-"], "coverage-cfg-checksum">, HelpText<"Emit CFG checksum for functions in .gcno files.">; def coverage_no_function_names_in_data : Flag<["-"], "coverage-no-function-names-in-data">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index f0b9f5cb54..d185caf55b 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -2117,7 +2117,7 @@ multiclass BooleanFFlag { defm : BooleanFFlag<"keep-inline-functions">, Group; -def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group; +def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group; def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group; diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index 3ee0910176..0839bc75e4 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -99,9 +99,13 @@ public: /// The code model to use (-mcmodel). std::string CodeModel; - /// The filename with path we use for coverage files. The extension will be - /// replaced. - std::string CoverageFile; + /// The filename with path we use for coverage data files. The runtime + /// allows further manipulation with the GCOV_PREFIX and GCOV_PREFIX_STRIP + /// environment variables. + std::string CoverageDataFile; + + /// The filename with path we use for coverage notes files. + std::string CoverageNotesFile; /// The version string to put into coverage files. char CoverageVersion[4]; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 1d74e4cd83..e296a4cc51 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -4208,18 +4208,24 @@ void CodeGenModule::EmitTargetMetadata() { } void CodeGenModule::EmitCoverageFile() { - if (!getCodeGenOpts().CoverageFile.empty()) { - if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) { - llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov"); - llvm::LLVMContext &Ctx = TheModule.getContext(); - llvm::MDString *CoverageFile = - llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile); - for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) { - llvm::MDNode *CU = CUNode->getOperand(i); - llvm::Metadata *Elts[] = {CoverageFile, CU}; - GCov->addOperand(llvm::MDNode::get(Ctx, Elts)); - } - } + if (getCodeGenOpts().CoverageDataFile.empty() && + getCodeGenOpts().CoverageNotesFile.empty()) + return; + + llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu"); + if (!CUNode) + return; + + llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov"); + llvm::LLVMContext &Ctx = TheModule.getContext(); + auto *CoverageDataFile = + llvm::MDString::get(Ctx, getCodeGenOpts().CoverageDataFile); + auto *CoverageNotesFile = + llvm::MDString::get(Ctx, getCodeGenOpts().CoverageNotesFile); + for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) { + llvm::MDNode *CU = CUNode->getOperand(i); + llvm::Metadata *Elts[] = {CoverageNotesFile, CoverageDataFile, CU}; + GCov->addOperand(llvm::MDNode::get(Ctx, Elts)); } } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 98724ee204..8922218d92 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -3622,13 +3622,13 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, if (C.getArgs().hasArg(options::OPT_c) || C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { - CmdArgs.push_back("-coverage-file"); - SmallString<128> CoverageFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { - CoverageFilename = FinalOutput->getValue(); - } else { - CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); - } + CmdArgs.push_back("-coverage-notes-file"); + SmallString<128> OutputFilename; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + OutputFilename = FinalOutput->getValue(); + else + OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); + SmallString<128> CoverageFilename = OutputFilename; if (llvm::sys::path::is_relative(CoverageFilename)) { SmallString<128> Pwd; if (!llvm::sys::fs::current_path(Pwd)) { @@ -3636,7 +3636,23 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, CoverageFilename.swap(Pwd); } } + llvm::sys::path::replace_extension(CoverageFilename, "gcno"); CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + + // Leave -fprofile-dir= an unused argument unless .gcda emission is + // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider + // the flag used. There is no -fno-profile-dir, so the user has no + // targeted way to suppress the warning. + if (Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_coverage)) { + CmdArgs.push_back("-coverage-data-file"); + if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) { + CoverageFilename = FProfileDir->getValue(); + llvm::sys::path::append(CoverageFilename, OutputFilename); + } + llvm::sys::path::replace_extension(CoverageFilename, "gcda"); + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + } } } } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 901a5a61de..619ea9cc23 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -639,7 +639,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) { - Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); + Opts.CoverageDataFile = Args.getLastArgValue(OPT_coverage_data_file); + Opts.CoverageNotesFile = Args.getLastArgValue(OPT_coverage_notes_file); Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); Opts.CoverageNoFunctionNamesInData = Args.hasArg(OPT_coverage_no_function_names_in_data); diff --git a/test/CodeGen/code-coverage.c b/test/CodeGen/code-coverage.c index 1b87d649dd..3aa23c698f 100644 --- a/test/CodeGen/code-coverage.c +++ b/test/CodeGen/code-coverage.c @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -emit-llvm -disable-red-zone -femit-coverage-data %s -o - | FileCheck %s // RUN: %clang_cc1 -emit-llvm -disable-red-zone -femit-coverage-data -coverage-no-function-names-in-data %s -o - | FileCheck %s --check-prefix WITHOUTNAMES +// RUN: %clang_cc1 -emit-llvm -disable-red-zone -femit-coverage-data -coverage-notes-file=aaa.gcno -coverage-data-file=bbb.gcda %s -o - | FileCheck %s --check-prefix GCOV_FILE_INFO // @@ -28,3 +29,6 @@ int test1(int a) { // CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]] // CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} } + +// GCOV_FILE_INFO: !llvm.gcov = !{![[GCOV:[0-9]+]]} +// GCOV_FILE_INFO: ![[GCOV]] = !{!"aaa.gcno", !"bbb.gcda", !{{[0-9]+}}} diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index 2b49069345..2952d0e111 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -66,6 +66,16 @@ // CHECK-PROFILE-ARCS: "-femit-coverage-data" // CHECK-NO-PROFILE-ARCS-NOT: "-femit-coverage-data" +// RUN: %clang -### -S -fprofile-dir=abc %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DIR-UNUSED %s +// RUN: %clang -### -S -ftest-coverage -fprofile-dir=abc %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DIR-UNUSED %s +// RUN: %clang -### -S -fprofile-arcs -fprofile-dir=abc %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DIR %s +// RUN: %clang -### -S --coverage -fprofile-dir=abc %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DIR %s +// RUN: %clang -### -S -fprofile-arcs -fno-profile-arcs -fprofile-dir=abc %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DIR-NEITHER %s +// CHECK-PROFILE-DIR: "-coverage-data-file" "abc +// CHECK-PROFILE-DIR-UNUSED: argument unused +// CHECK-PROFILE-DIR-UNUSED-NOT: "-coverage-data-file" "abc +// CHECK-PROFILE-DIR-NEITHER-NOT: argument unused + // RUN: %clang -### -S -fprofile-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-LLVM %s // RUN: %clang -### -S -fprofile-instr-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s // RUN: %clang -### -S -fprofile-generate=/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-DIR %s @@ -212,7 +222,6 @@ // RUN: -fdefer-pop -fno-defer-pop \ // RUN: -fprefetch-loop-arrays -fno-prefetch-loop-arrays \ // RUN: -fprofile-correction -fno-profile-correction \ -// RUN: -fprofile-dir=bar \ // RUN: -fprofile-values -fno-profile-values \ // RUN: -frounding-math -fno-rounding-math \ // RUN: -fsee -fno-see \ @@ -290,7 +299,6 @@ // RUN: -fkeep-inline-functions \ // RUN: -fno-keep-inline-functions \ // RUN: -freorder-blocks \ -// RUN: -fprofile-dir=/rand/dir \ // RUN: -falign-functions \ // RUN: -falign-functions=1 \ // RUN: -ffloat-store \ @@ -357,7 +365,6 @@ // CHECK-WARNING-DAG: optimization flag '-fkeep-inline-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-fno-keep-inline-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported -// CHECK-WARNING-DAG: optimization flag '-fprofile-dir=/rand/dir' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions=1' is not supported // CHECK-WARNING-DAG: optimization flag '-ffloat-store' is not supported diff --git a/test/Driver/coverage_no_integrated_as.c b/test/Driver/coverage_no_integrated_as.c index 9a0a0c203e..9acab9bbd1 100644 --- a/test/Driver/coverage_no_integrated_as.c +++ b/test/Driver/coverage_no_integrated_as.c @@ -17,7 +17,7 @@ // RUN: %clang -### -c -fprofile-arcs -no-integrated-as %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION-REL-PATH %s -// CHECK-GCNO-DEFAULT-LOCATION: "-coverage-file" "{{.*}}{{/|\\\\}}coverage_no_integrated_as.c" -// CHECK-GCNO-DEFAULT-LOCATION-NOT: "-coverage-file" "/tmp/{{.*}}/coverage_no_integrated_as.c" -// CHECK-GCNO-LOCATION: "-coverage-file" "{{.*}}/foo/bar.o" -// CHECK-GCNO-LOCATION-REL-PATH: "-coverage-file" "{{.*}}{{/|\\\\}}foo/bar.o" +// CHECK-GCNO-DEFAULT-LOCATION: "-coverage-notes-file" "{{.*}}{{/|\\\\}}coverage_no_integrated_as.c" +// CHECK-GCNO-DEFAULT-LOCATION-NOT: "-coverage-notes-file" "/tmp/{{.*}}/coverage_no_integrated_as.c" +// CHECK-GCNO-LOCATION: "-coverage-notes-file" "{{.*}}/foo/bar.gcno" +// CHECK-GCNO-LOCATION-REL-PATH: "-coverage-notes-file" "{{.*}}{{/|\\\\}}foo/bar.gcno"