diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -167,6 +167,7 @@ std::string RecordCommandLine; std::map DebugPrefixMap; + std::map ProfilePrefixMap; /// The ABI to use for passing floating point arguments. std::string FloatABI; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1977,6 +1977,10 @@ : Joined<["-"], "fdebug-prefix-map=">, Group, Flags<[CC1Option,CC1AsOption]>, HelpText<"remap file source paths in debug info">; +def fprofile_prefix_map_QA + : Joined<["-"], "fprofile-prefix-map=">, Group, + Flags<[CC1Option,CC1AsOption]>, + HelpText<"remap file source paths in coverage info">; def ffile_prefix_map_EQ : Joined<["-"], "ffile-prefix-map=">, Group, HelpText<"remap file source paths in debug info and predefined preprocessor macros">; diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h --- a/clang/lib/CodeGen/CoverageMappingGen.h +++ b/clang/lib/CodeGen/CoverageMappingGen.h @@ -60,14 +60,16 @@ llvm::SmallDenseMap FileEntries; std::vector FunctionNames; std::vector FunctionRecords; + std::map ProfilePrefixMap; + + std::string normalizeFilename(StringRef Filename); /// Emit a function record. void emitFunctionMappingRecord(const FunctionInfo &Info, uint64_t FilenamesRef); public: - CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) - : CGM(CGM), SourceInfo(SourceInfo) {} + CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo); CoverageSourceInfo &getSourceInfo() const { return SourceInfo; diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1291,13 +1291,6 @@ } }; -std::string normalizeFilename(StringRef Filename) { - llvm::SmallString<256> Path(Filename); - llvm::sys::fs::make_absolute(Path); - llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - return std::string(Path); -} - } // end anonymous namespace static void dump(llvm::raw_ostream &OS, StringRef FunctionName, @@ -1330,6 +1323,23 @@ } } +CoverageMappingModuleGen::CoverageMappingModuleGen( + CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) + : CGM(CGM), SourceInfo(SourceInfo) { + ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap; +} + +std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { + llvm::SmallString<256> Path(Filename); + llvm::sys::fs::make_absolute(Path); + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + for (const auto &Entry : ProfilePrefixMap) { + if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) + break; + } + return Path.str().str(); +} + static std::string getInstrProfSection(const CodeGenModule &CGM, llvm::InstrProfSectKind SK) { return llvm::getInstrProfSectionName( diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -657,6 +657,21 @@ } } +/// Add a CC1 and CC1AS option to specify the coverage file path prefix map. +static void addProfilePrefixMapArg(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fprofile_prefix_map_QA)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else + CmdArgs.push_back(Args.MakeArgString("-fprofile-prefix-map=" + Map)); + A->claim(); + } +} + /// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disabled, while the slp vectorizer is /// enabled. @@ -1340,6 +1355,7 @@ } addMacroPrefixMapArg(D, Args, CmdArgs); + addProfilePrefixMapArg(D, Args, CmdArgs); } // FIXME: Move to target hook. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -811,6 +811,12 @@ {std::string(Split.first), std::string(Split.second)}); } + for (const auto &Arg : Args.getAllArgValues(OPT_fprofile_prefix_map_QA)) { + auto Split = StringRef(Arg).split('='); + Opts.ProfilePrefixMap.insert( + {std::string(Split.first), std::string(Split.second)}); + } + if (const Arg *A = Args.getLastArg(OPT_emit_llvm_uselists, OPT_no_emit_llvm_uselists)) Opts.EmitLLVMUseLists = A->getOption().getID() == OPT_emit_llvm_uselists; diff --git a/clang/test/Driver/debug-prefix-map.c b/clang/test/Driver/debug-prefix-map.c --- a/clang/test/Driver/debug-prefix-map.c +++ b/clang/test/Driver/debug-prefix-map.c @@ -1,28 +1,39 @@ // RUN: %clang -### -fdebug-prefix-map=old %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-INVALID // RUN: %clang -### -fmacro-prefix-map=old %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-INVALID +// RUN: %clang -### -fprofile-prefix-map=old %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-INVALID // RUN: %clang -### -ffile-prefix-map=old %s 2>&1 | FileCheck %s -check-prefix CHECK-FILE-INVALID // RUN: %clang -### -fdebug-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-SIMPLE // RUN: %clang -### -fmacro-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-SIMPLE +// RUN: %clang -### -fprofile-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-SIMPLE // RUN: %clang -### -ffile-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-SIMPLE // RUN: %clang -### -ffile-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-SIMPLE +// RUN: %clang -### -ffile-prefix-map=old=new %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-SIMPLE // RUN: %clang -### -fdebug-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-COMPLEX // RUN: %clang -### -fmacro-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-COMPLEX +// RUN: %clang -### -fprofile-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-COMPLEX // RUN: %clang -### -ffile-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-COMPLEX // RUN: %clang -### -ffile-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-COMPLEX +// RUN: %clang -### -ffile-prefix-map=old=n=ew %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-COMPLEX // RUN: %clang -### -fdebug-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-EMPTY // RUN: %clang -### -fmacro-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-EMPTY +// RUN: %clang -### -fprofile-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-EMPTY // RUN: %clang -### -ffile-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-DEBUG-EMPTY // RUN: %clang -### -ffile-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-MACRO-EMPTY +// RUN: %clang -### -ffile-prefix-map=old= %s 2>&1 | FileCheck %s -check-prefix CHECK-PROFILE-EMPTY // CHECK-DEBUG-INVALID: error: invalid argument 'old' to -fdebug-prefix-map // CHECK-MACRO-INVALID: error: invalid argument 'old' to -fmacro-prefix-map +// CHECK-PROFILE-INVALID: error: invalid argument 'old' to -fprofile-prefix-map // CHECK-FILE-INVALID: error: invalid argument 'old' to -ffile-prefix-map // CHECK-DEBUG-SIMPLE: fdebug-prefix-map=old=new // CHECK-MACRO-SIMPLE: fmacro-prefix-map=old=new +// CHECK-PROFILE-SIMPLE: fprofile-prefix-map=old=new // CHECK-DEBUG-COMPLEX: fdebug-prefix-map=old=n=ew // CHECK-MACRO-COMPLEX: fmacro-prefix-map=old=n=ew +// CHECK-PROFILE-COMPLEX: fprofile-prefix-map=old=n=ew // CHECK-DEBUG-EMPTY: fdebug-prefix-map=old= // CHECK-MACRO-EMPTY: fmacro-prefix-map=old= +// CHECK-PROFILE-EMPTY: fprofile-prefix-map=old= diff --git a/clang/test/Profile/profile-prefix-map.c b/clang/test/Profile/profile-prefix-map.c new file mode 100644 --- /dev/null +++ b/clang/test/Profile/profile-prefix-map.c @@ -0,0 +1,14 @@ +// %s expands to an absolute path, so to test relative paths we need to create a +// clean directory, put the source there, and cd into it. +// RUN: rm -rf %t +// RUN: mkdir -p %t/root/nested +// RUN: echo "void f1() {}" > %t/root/nested/profile-prefix-map.c +// RUN: cd %t/root + +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s +// +// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\01.*root.*nested.*profile-prefix-map\.c}} + +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s --implicit-check-not=root +// +// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\01[^/]*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}