Diego Novillo <dnovi...@google.com> writes: > This update incorporates: > > - Documentation fix to clarify that directories are created at runtime. > - Allow -fprofile-generate and -fprofile-instr-generate to have the > usual last-wins semantics. > - Move __llvm_profile_recursive_mkdir into its own file in the runtime > library. > > OK to commit?
I have a couple more comments about the clang patch below, then it's good. The compiler-rt patch LGTM. > Thanks. Diego. > > diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst > index cd1b2b3..20ee569 100644 > --- a/docs/UsersManual.rst > +++ b/docs/UsersManual.rst > @@ -1488,6 +1488,45 @@ instrumentation: > profile. As you make changes to your code, clang may no longer be able to > use the profile data. It will warn you when this happens. > > +Profile generation and use can also be controlled by the GCC-compatible flags > +``-fprofile-generate`` and ``-fprofile-use``. Although these flags are > +semantically equivalent to their GCC counterparts, they *do not* handle > +GCC-compatible profiles. They are only meant to implement GCC's semantics > +with respect to profile creation and use. > + > +.. option:: -fprofile-generate[=<dirname>] > + > + Without any other arguments, ``-fprofile-generate`` behaves identically to > + ``-fprofile-instr-generate``. When given a directory name, it generates the > + profile file ``default.profraw`` in the directory named ``dirname``. If > + ``dirname`` does not exist, it will be created at runtime. The environment > + variable ``LLVM_PROFILE_FILE`` can be used to override the directory and > + filename for the profile file at runtime. For example, > + > + .. code-block:: console > + > + $ clang++ -O2 -fprofile-generate=yyy/zzz code.cc -o code > + > + When ``code`` is executed, the profile will be written to the file > + ``yyy/zzz/default.profraw``. This can be altered at runtime via the > + ``LLVM_PROFILE_FILE`` environment variable: > + > + .. code-block:: console > + > + $ LLVM_PROFILE_FILE=/tmp/myprofile/code.profraw ./code > + > + The above invocation will produce the profile file > + ``/tmp/myprofile/code.profraw`` instead of ``yyy/zzz/default.profraw``. > + Notice that ``LLVM_PROFILE_FILE`` overrides the directory *and* the file > + name for the profile file. > + > +.. option:: -fprofile-use[=<pathname>] > + > + Without any other arguments, ``-fprofile-use`` behaves identically to > + ``-fprofile-instr-use``. Otherwise, if ``pathname`` is the full path to a > + profile file, it reads from that file. If ``pathname`` is a directory name, > + it reads from ``pathname/default.profdata``. > + > > Controlling Size of Debug Information > ------------------------------------- > diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td > index df90371..1202724 100644 > --- a/include/clang/Driver/Options.td > +++ b/include/clang/Driver/Options.td > @@ -422,13 +422,24 @@ def fprofile_instr_generate : Flag<["-"], > "fprofile-instr-generate">, > def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">, > Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<file>">, > HelpText<"Generate instrumented code to collect execution counts into > <file> (overridden by LLVM_PROFILE_FILE env var)">; > -def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>; > +def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>, > + Flags<[DriverOption]>; > def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, > Group<f_Group>, Flags<[CC1Option]>, > HelpText<"Use instrumentation data for profile-guided optimization">; > def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, > Group<f_Group>, Flags<[CC1Option]>, > HelpText<"Generate coverage mapping to enable code coverage analysis">; > +def fprofile_generate : Flag<["-"], "fprofile-generate">, > + Alias<fprofile_instr_generate>; > +def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, > + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">, > + HelpText<"Generate instrumented code to collect execution counts into > <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">; > +def fprofile_use : Flag<["-"], "fprofile-use">, Group<f_Group>, > + Alias<fprofile_instr_use>; > +def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, > + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<pathname>">, > + HelpText<"Use instrumentation data for profile-guided optimization. If > pathname is a directory, it reads from <pathname>/default.profile. Otherwise, > it reads from file <pathname>.">; This should say "default.profdata" here to match the code. > > def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, > HelpText<"Enable the 'blocks' language feature">; > @@ -904,7 +915,6 @@ def fpie : Flag<["-"], "fpie">, Group<f_Group>; > def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>; > def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>; > def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>; > -def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>; > def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; > def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, > Group<clang_ignored_f_Group>; > def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, > Flags<[CC1Option]>, > @@ -1794,8 +1804,6 @@ defm : BooleanFFlag<"keep-inline-functions">, > Group<clang_ignored_gcc_optimizati > > def fprofile_dir : Joined<["-"], "fprofile-dir=">, > Group<clang_ignored_gcc_optimization_f_Group>; > > -defm profile_use : BooleanFFlag<"profile-use">, > Group<clang_ignored_gcc_optimization_f_Group>; > -def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, > Group<clang_ignored_gcc_optimization_f_Group>; > def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>; > > defm align_functions : BooleanFFlag<"align-functions">, > Group<clang_ignored_gcc_optimization_f_Group>; > diff --git a/include/clang/Frontend/CodeGenOptions.h > b/include/clang/Frontend/CodeGenOptions.h > index 66597bd..53246bc 100644 > --- a/include/clang/Frontend/CodeGenOptions.h > +++ b/include/clang/Frontend/CodeGenOptions.h > @@ -155,6 +155,7 @@ public: > std::vector<std::string> DependentLibraries; > > /// Name of the profile file to use as output for -fprofile-instr-generate > + /// and -fprofile-generate. > std::string InstrProfileOutput; > > /// Name of the profile file to use with -fprofile-sample-use. > diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp > index 463503b..fd70868 100644 > --- a/lib/Driver/ToolChains.cpp > +++ b/lib/Driver/ToolChains.cpp > @@ -303,6 +303,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, > if (!(Args.hasFlag(options::OPT_fprofile_arcs, > options::OPT_fno_profile_arcs, > false) || > Args.hasArg(options::OPT_fprofile_generate) || > + Args.hasArg(options::OPT_fprofile_generate_EQ) || > Args.hasArg(options::OPT_fprofile_instr_generate) || > Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || > Args.hasArg(options::OPT_fcreate_profile) || > diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp > index 1795ccf..ee70793 100644 > --- a/lib/Driver/Tools.cpp > +++ b/lib/Driver/Tools.cpp > @@ -2298,6 +2298,7 @@ static void addProfileRT(const ToolChain &TC, const > ArgList &Args, > if (!(Args.hasFlag(options::OPT_fprofile_arcs, > options::OPT_fno_profile_arcs, > false) || > Args.hasArg(options::OPT_fprofile_generate) || > + Args.hasArg(options::OPT_fprofile_generate_EQ) || > Args.hasArg(options::OPT_fprofile_instr_generate) || > Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || > Args.hasArg(options::OPT_fcreate_profile) || > @@ -3533,22 +3534,34 @@ void Clang::ConstructJob(Compilation &C, const > JobAction &JA, > Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); > > if ((Args.hasArg(options::OPT_fprofile_instr_generate) || > - Args.hasArg(options::OPT_fprofile_instr_generate_EQ)) && > + Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || > + Args.hasArg(options::OPT_fprofile_generate_EQ)) && > (Args.hasArg(options::OPT_fprofile_instr_use) || > - Args.hasArg(options::OPT_fprofile_instr_use_EQ))) > + Args.hasArg(options::OPT_fprofile_instr_use_EQ) || > + Args.hasArg(options::OPT_fprofile_use_EQ))) > D.Diag(diag::err_drv_argument_not_allowed_with) > << "-fprofile-instr-generate" > << "-fprofile-instr-use"; > > if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_generate_EQ)) > A->render(Args, CmdArgs); > - else > + else if (Arg *A = Args.getLastArg(options::OPT_fprofile_generate_EQ)) { > + SmallString<128> Path(A->getValue()); > + llvm::sys::path::append(Path, "default.profraw"); > + CmdArgs.push_back( > + Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); > + } else > Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); I think we want a single call to getLastArg here, with all four variants. As is, it isn't last wins - it uses -fprofile-instr-generate=, and if there isn't one of those then it uses -fprofile-generate=, etc. Also, how is -fprofile-generate handled right now? It seems to be missing. Anyways, something like (untested): if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_generate_EQ, options::OPT_fprofile_instr_generate, options::OPT_fprofile_generate_EQ, options::OPT_fprofile_generate)) { if (A->getNumValues()) { SmallString<128> Path(A->getValue()); if (A->getOption().matches(options::OPT_fprofile_generate_EQ)) llvm::sys::path::append(Path, "default.profraw"); CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); } else CmdArgs.push_back("-fprofile-instr-generate"); > > if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ)) > A->render(Args, CmdArgs); > - else if (Args.hasArg(options::OPT_fprofile_instr_use)) > - CmdArgs.push_back("-fprofile-instr-use=pgo-data"); > + else if (Arg *A = Args.getLastArg(options::OPT_fprofile_use_EQ, > + options::OPT_fprofile_instr_use)) { > + SmallString<128> Path(A->getNumValues() == 0 ? "" : A->getValue()); > + if (Path.empty() || llvm::sys::fs::is_directory(Path)) > + llvm::sys::path::append(Path, "default.profdata"); > + CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instr-use=") + > Path)); > + } Similarly here. > > if (Args.hasArg(options::OPT_ftest_coverage) || > Args.hasArg(options::OPT_coverage)) > @@ -3560,7 +3573,9 @@ void Clang::ConstructJob(Compilation &C, const > JobAction &JA, > > if (Args.hasArg(options::OPT_fcoverage_mapping) && > !(Args.hasArg(options::OPT_fprofile_instr_generate) || > - Args.hasArg(options::OPT_fprofile_instr_generate_EQ))) > + Args.hasArg(options::OPT_fprofile_generate) || > + Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || > + Args.hasArg(options::OPT_fprofile_generate_EQ))) > D.Diag(diag::err_drv_argument_only_allowed_with) > << "-fcoverage-mapping" > << "-fprofile-instr-generate"; > diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c > index 68890a7..74cdf5b 100644 > --- a/test/Driver/clang_f_opts.c > +++ b/test/Driver/clang_f_opts.c > @@ -66,6 +66,40 @@ > // CHECK-PROFILE-ARCS: "-femit-coverage-data" > // CHECK-NO-PROFILE-ARCS-NOT: "-femit-coverage-data" > > +// RUN: %clang -### -S -fprofile-generate %s 2>&1 | FileCheck > -check-prefix=CHECK-PROFILE-GENERATE %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 > +// RUN: %clang -### -S -fprofile-instr-generate=/tmp/somefile.profraw %s > 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-FILE %s Some variants like the following would show that the last-one-wins semantics work correctly: %clang -### -S -fprofile-instr-generate=/tmp/foo.profraw -fprofile-generate=/tmp/somefile.profraw %s > +// RUN: %clang -### -S -fprofile-generate -fprofile-use %s 2>&1 | FileCheck > -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate -fprofile-use=dir %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use=file %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use=dir %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use %s 2>&1 > | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use=file %s > 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use=dir %s > 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-instr-use %s > 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-instr-generate=file > -fprofile-instr-use=file %s 2>&1 | FileCheck > -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use=dir %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use %s 2>&1 | > FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use=file %s > 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s > +// CHECK-PROFILE-GENERATE: "-fprofile-instr-generate" > +// CHECK-PROFILE-GENERATE-DIR: > "-fprofile-instr-generate=/some/dir/default.profraw" > +// CHECK-PROFILE-GENERATE-FILE: > "-fprofile-instr-generate=/tmp/somefile.profraw" > +// CHECK-NO-MIX-GEN-USE: '-fprofile-instr-generate' not allowed with > '-fprofile-instr-use' > + > +// RUN: %clang -### -S -fprofile-use %s 2>&1 | FileCheck > -check-prefix=CHECK-PROFILE-USE %s > +// RUN: %clang -### -S -fprofile-instr-use %s 2>&1 | FileCheck > -check-prefix=CHECK-PROFILE-USE %s > +// RUN: mkdir -p %t.d/some/dir > +// RUN: %clang -### -S -fprofile-use=%t.d/some/dir %s 2>&1 | FileCheck > -check-prefix=CHECK-PROFILE-USE-DIR %s > +// RUN: %clang -### -S -fprofile-instr-use=/tmp/somefile.prof %s 2>&1 | > FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s > +// CHECK-PROFILE-USE: "-fprofile-instr-use=default.profdata" > +// CHECK-PROFILE-USE-DIR: > "-fprofile-instr-use={{.*}}.d/some/dir/default.profdata" > +// CHECK-PROFILE-USE-FILE: "-fprofile-instr-use=/tmp/somefile.prof" > + > // RUN: %clang -### -S -fvectorize %s 2>&1 | FileCheck > -check-prefix=CHECK-VECTORIZE %s > // RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck > -check-prefix=CHECK-VECTORIZE %s > // RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck > -check-prefix=CHECK-NO-VECTORIZE %s > @@ -162,7 +196,6 @@ > // RUN: -fprefetch-loop-arrays -fno-prefetch-loop-arrays > \ > // RUN: -fprofile-correction -fno-profile-correction > \ > // RUN: -fprofile-dir=bar > \ > -// RUN: -fprofile-use -fprofile-use=zed -fno-profile-use > \ > // RUN: -fprofile-values -fno-profile-values > \ > // RUN: -frounding-math -fno-rounding-math > \ > // RUN: -fsee -fno-see > \ > @@ -242,8 +275,6 @@ > // RUN: -fno-keep-inline-functions > \ > // RUN: -freorder-blocks > \ > // RUN: -fprofile-dir=/rand/dir > \ > -// RUN: -fprofile-use > \ > -// RUN: -fprofile-use=/rand/dir > \ > // RUN: -falign-functions > \ > // RUN: -falign-functions=1 > \ > // RUN: -ffloat-store > \ > @@ -312,8 +343,6 @@ > // 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 '-fprofile-use' is not supported > -// CHECK-WARNING-DAG: optimization flag '-fprofile-use=/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/Profile/Inputs/gcc-flag-compatibility.proftext > b/test/Profile/Inputs/gcc-flag-compatibility.proftext > new file mode 100644 > index 0000000..99d41bb > --- /dev/null > +++ b/test/Profile/Inputs/gcc-flag-compatibility.proftext > @@ -0,0 +1,5 @@ > +main > +4 > +2 > +1 > +100 > diff --git a/test/Profile/gcc-flag-compatibility.c > b/test/Profile/gcc-flag-compatibility.c > new file mode 100644 > index 0000000..53a7651 > --- /dev/null > +++ b/test/Profile/gcc-flag-compatibility.c > @@ -0,0 +1,48 @@ > +// Tests for -fprofile-generate and -fprofile-use flag compatibility. These > two > +// flags behave similarly to their GCC counterparts: > +// > +// -fprofile-generate Generates the profile file ./default.profraw > +// -fprofile-generate=<dir> Generates the profile file > <dir>/default.profraw > +// -fprofile-use Uses the profile file ./default.profdata > +// -fprofile-use=<dir> Uses the profile file <dir>/default.profdata > +// -fprofile-use=<dir>/file Uses the profile file <dir>/file > + > +// Check that -fprofile-generate uses the runtime default profile file. > +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate | FileCheck > -check-prefix=PROFILE-GEN %s > +// PROFILE-GEN: @__llvm_profile_runtime = external global i32 > +// PROFILE-GEN-NOT: call void @__llvm_profile_override_default_filename > +// PROFILE-GEN-NOT: declare void > @__llvm_profile_override_default_filename(i8*) > + > +// Check that -fprofile-generate=/path/to generates /path/to/default.profraw > +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to | > FileCheck -check-prefix=PROFILE-GEN-EQ %s > +// PROFILE-GEN-EQ: private constant [25 x i8] c"/path/to/default.profraw\00" > +// PROFILE-GEN-EQ: call void @__llvm_profile_override_default_filename(i8* > getelementptr inbounds ([25 x i8], [25 x i8]* @0, i32 0, i32 0)) > +// PROFILE-GEN-EQ: declare void > @__llvm_profile_override_default_filename(i8*) > + > +// Check that -fprofile-use reads default.profdata > +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o > default.profdata > +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S > -fprofile-use | FileCheck -check-prefix=PROFILE-USE-1 %s > +// PROFILE-USE-1: = !{!"branch_weights", i32 101, i32 2} > + > +// Check that -fprofile-use=some/path reads some/path/default.profdata > +// RUN: rm -rf %t.dir > +// RUN: mkdir -p %t.dir/some/path > +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o > %t.dir/some/path/default.profdata > +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S > -fprofile-use=%t.dir/some/path | FileCheck -check-prefix=PROFILE-USE-2 %s > +// PROFILE-USE-2: = !{!"branch_weights", i32 101, i32 2} > + > +// Check that -fprofile-use=some/path/file.prof reads some/path/file.prof > +// RUN: rm -rf %t.dir > +// RUN: mkdir -p %t.dir/some/path > +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o > %t.dir/some/path/file.prof > +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S > -fprofile-use=%t.dir/some/path/file.prof | FileCheck > -check-prefix=PROFILE-USE-3 %s > +// PROFILE-USE-3: = !{!"branch_weights", i32 101, i32 2} > + > +int X = 0; > + > +int main() { > + int i; > + for (i = 0; i < 100; i++) > + X += i; > + return 0; > +} > > diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt > index d0714e0..d03409f 100644 > --- a/lib/profile/CMakeLists.txt > +++ b/lib/profile/CMakeLists.txt > @@ -7,7 +7,8 @@ set(PROFILE_SOURCES > InstrProfilingFile.c > InstrProfilingPlatformDarwin.c > InstrProfilingPlatformOther.c > - InstrProfilingRuntime.cc) > + InstrProfilingRuntime.cc > + InstrProfilingUtil.c) > > if(APPLE) > add_compiler_rt_osx_static_runtime(clang_rt.profile_osx > diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c > index e32e97f..aec2328 100644 > --- a/lib/profile/GCDAProfiling.c > +++ b/lib/profile/GCDAProfiling.c > @@ -20,6 +20,8 @@ > |* > > \*===----------------------------------------------------------------------===*/ > > +#include "InstrProfilingUtil.h" > + > #include <errno.h> > #include <fcntl.h> > #include <stdio.h> > @@ -27,17 +29,9 @@ > #include <string.h> > #include <sys/mman.h> > #include <sys/file.h> > -#ifdef _WIN32 > -#include <direct.h> > -#endif > > #define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) > > -#if !I386_FREEBSD > -#include <sys/stat.h> > -#include <sys/types.h> > -#endif > - > #if !defined(_MSC_VER) && !I386_FREEBSD > #include <stdint.h> > #endif > @@ -52,7 +46,6 @@ typedef unsigned long long uint64_t; > typedef unsigned char uint8_t; > typedef unsigned int uint32_t; > typedef unsigned long long uint64_t; > -int mkdir(const char*, unsigned short); > #endif > > /* #define DEBUG_GCDAPROFILING */ > @@ -209,21 +202,6 @@ static char *mangle_filename(const char *orig_filename) { > return new_filename; > } > > -static void recursive_mkdir(char *path) { > - int i; > - > - for (i = 1; path[i] != '\0'; ++i) { > - if (path[i] != '/') continue; > - path[i] = '\0'; > -#ifdef _WIN32 > - _mkdir(path); > -#else > - mkdir(path, 0755); /* Some of these will fail, ignore it. */ > -#endif > - path[i] = '/'; > - } > -} > - > static int map_file() { > fseek(output_file, 0L, SEEK_END); > file_size = ftell(output_file); > @@ -283,7 +261,7 @@ void llvm_gcda_start_file(const char *orig_filename, > const char version[4], > fd = open(filename, O_RDWR | O_CREAT, 0644); > if (fd == -1) { > /* Try creating the directories first then opening the file. */ > - recursive_mkdir(filename); > + __llvm_profile_recursive_mkdir(filename); > fd = open(filename, O_RDWR | O_CREAT, 0644); > if (fd == -1) { > /* Bah! It's hopeless. */ > diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h > index 84b673c..3778a88 100644 > --- a/lib/profile/InstrProfiling.h > +++ b/lib/profile/InstrProfiling.h > @@ -64,7 +64,7 @@ uint64_t *__llvm_profile_end_counters(void); > * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment > variable, > * or if that's not set, the last name given to > * \a __llvm_profile_override_default_filename(), or if that's not set, > - * \c "default.profdata". > + * \c "default.profraw". > */ > int __llvm_profile_write_file(void); > > diff --git a/lib/profile/InstrProfilingFile.c > b/lib/profile/InstrProfilingFile.c > index 0102a25..9402238 100644 > --- a/lib/profile/InstrProfilingFile.c > +++ b/lib/profile/InstrProfilingFile.c > @@ -8,6 +8,7 @@ > > \*===----------------------------------------------------------------------===*/ > > #include "InstrProfiling.h" > +#include "InstrProfilingUtil.h" > #include <errno.h> > #include <stdio.h> > #include <stdlib.h> > @@ -84,6 +85,13 @@ static void truncateCurrentFile(void) { > if (!Filename || !Filename[0]) > return; > > + /* Create the directory holding the file, if needed. */ > + if (strchr(Filename, '/')) { > + char *Copy = malloc(strlen(Filename) + 1); > + strcpy(Copy, Filename); > + __llvm_profile_recursive_mkdir(Copy); > + } > + > /* Truncate the file. Later we'll reopen and append. */ > File = fopen(Filename, "w"); > if (!File) > diff --git a/lib/profile/InstrProfilingUtil.c > b/lib/profile/InstrProfilingUtil.c > new file mode 100644 > index 0000000..e146dfc > --- /dev/null > +++ b/lib/profile/InstrProfilingUtil.c > @@ -0,0 +1,35 @@ > +/*===- InstrProfilingUtil.c - Support library for PGO instrumentation > -----===*\ > +|* > +|* The LLVM Compiler Infrastructure > +|* > +|* This file is distributed under the University of Illinois Open Source > +|* License. See LICENSE.TXT for details. > +|* > +\*===----------------------------------------------------------------------===*/ > + > +#include "InstrProfilingUtil.h" > + > +#ifdef _WIN32 > +#include <direct.h> > +#elif I386_FREEBSD > +int mkdir(const char*, unsigned short); > +#else > +#include <sys/stat.h> > +#include <sys/types.h> > +#endif > + > +__attribute__((visibility("hidden"))) > +void __llvm_profile_recursive_mkdir(char *path) { > + int i; > + > + for (i = 1; path[i] != '\0'; ++i) { > + if (path[i] != '/') continue; > + path[i] = '\0'; > +#ifdef _WIN32 > + _mkdir(path); > +#else > + mkdir(path, 0755); /* Some of these will fail, ignore it. */ > +#endif > + path[i] = '/'; > + } > +} > diff --git a/lib/profile/InstrProfilingUtil.h > b/lib/profile/InstrProfilingUtil.h > new file mode 100644 > index 0000000..756b18e > --- /dev/null > +++ b/lib/profile/InstrProfilingUtil.h > @@ -0,0 +1,16 @@ > +/*===- InstrProfilingUtil.h - Support library for PGO instrumentation > -----===*\ > +|* > +|* The LLVM Compiler Infrastructure > +|* > +|* This file is distributed under the University of Illinois Open Source > +|* License. See LICENSE.TXT for details. > +|* > +\*===----------------------------------------------------------------------===*/ > + > +#ifndef PROFILE_INSTRPROFILINGUTIL_H > +#define PROFILE_INSTRPROFILINGUTIL_H > + > +/*! \brief Create a directory tree. */ > +void __llvm_profile_recursive_mkdir(char *Pathname); > + > +#endif /* PROFILE_INSTRPROFILINGUTIL_H */ > diff --git a/test/profile/Inputs/gcc-flag-compatibility.c > b/test/profile/Inputs/gcc-flag-compatibility.c > new file mode 100644 > index 0000000..1c07bb1 > --- /dev/null > +++ b/test/profile/Inputs/gcc-flag-compatibility.c > @@ -0,0 +1,8 @@ > +int X = 0; > + > +int main() { > + int i; > + for (i = 0; i < 100; i++) > + X += i; > + return 0; > +} > diff --git a/test/profile/gcc-flag-compatibility.test > b/test/profile/gcc-flag-compatibility.test > new file mode 100644 > index 0000000..8e8b55d > --- /dev/null > +++ b/test/profile/gcc-flag-compatibility.test > @@ -0,0 +1,17 @@ > +RUN: mkdir -p %t.d > +RUN: %clang_profgen_gcc=%t.d/d1/d2 -o %t.d/code > %S/Inputs/gcc-flag-compatibility.c > + > +# Test that the instrumented code writes to %t.d/d1/d2/default.profraw > +RUN: %run %t.d/code > +RUN: llvm-profdata merge -o %t.profdata %t.d/d1/d2/default.profraw > + > +# Test that we can override the directory and file name with > LLVM_PROFILE_FILE. > +RUN: env LLVM_PROFILE_FILE=%t.d/x1/prof.raw %run %t.d/code > +RUN: llvm-profdata merge -o %t.profdata %t.d/x1/prof.raw > + > +# Test that we can specify a directory with -fprofile-use. > +RUN: llvm-profdata merge -o %t.d/default.profdata %t.d/x1/prof.raw > +RUN: %clang_profuse_gcc=%t.d -o %t.d/code %S/Inputs/gcc-flag-compatibility.c > + > +# Test that we can specify a file with -fprofile-use. > +RUN: %clang_profuse_gcc=%t.profdata -o %t.d/code > %S/Inputs/gcc-flag-compatibility.c > diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg > index e4910ab..b1b44a1 100644 > --- a/test/profile/lit.cfg > +++ b/test/profile/lit.cfg > @@ -45,6 +45,8 @@ def build_invocation(compile_flags): > config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) > config.substitutions.append( ("%clang_profgen ", > build_invocation(clang_cflags) + " -fprofile-instr-generate ") ) > config.substitutions.append( ("%clang_profuse=", > build_invocation(clang_cflags) + " -fprofile-instr-use=") ) > +config.substitutions.append( ("%clang_profgen_gcc=", > build_invocation(clang_cflags) + " -fprofile-generate=") ) > +config.substitutions.append( ("%clang_profuse_gcc=", > build_invocation(clang_cflags) + " -fprofile-use=") ) > > if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: > config.unsupported = True _______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits