davidxl created this revision. davidxl added reviewers: bogner, rsmith. davidxl added subscribers: cfe-commits, llvm-commits. Herald added subscribers: srhines, danalbert, tberghammer.
With PGO, the instrumented binary needs to dump __llvm_prf_data, __llvm_prf_cnts, and __llvm_prf_names data sections. The runtime needs to figure out the start and end addresses of the sections. The way it is implemented for Linux is emit function calls during start up time to register the __llvm_profile_data variables created for the functions, and runtime library tracks the start and end. On Darwin, special section symbol is used so this is avoided. This is not only inefficient, but also wastes lots of space in text. This patch proposes using linker script to solve the problem. The changes in clang FE is basically refactoring. The core changes are in projects/compiler_rt/profile and llvm. http://reviews.llvm.org/D13319 Files: include/clang/Driver/ToolChain.h lib/Driver/SanitizerArgs.cpp lib/Driver/ToolChain.cpp lib/Driver/ToolChains.cpp lib/Driver/ToolChains.h lib/Driver/Tools.cpp lib/Transforms/Instrumentation/InstrProfiling.cpp lib/profile/CMakeLists.txt lib/profile/InstrProfilingPlatformOther.c lib/profile/prf_data.x test/Instrumentation/InstrProfiling/platform.ll
Index: lib/profile/prf_data.x =================================================================== --- /dev/null +++ lib/profile/prf_data.x @@ -0,0 +1,8 @@ +SECTIONS { + __llvm_prf_data_start = ADDR(__llvm_prf_data); + __llvm_prf_data_end = ADDR(__llvm_prf_data) + SIZEOF(__llvm_prf_data); + __llvm_prf_cnts_start = ADDR(__llvm_prf_cnts); + __llvm_prf_cnts_end = ADDR(__llvm_prf_cnts) + SIZEOF(__llvm_prf_cnts); + __llvm_prf_names_start = ADDR(__llvm_prf_names); + __llvm_prf_names_end = ADDR(__llvm_prf_names) + SIZEOF(__llvm_prf_names); +}; Index: lib/profile/InstrProfilingPlatformOther.c =================================================================== --- lib/profile/InstrProfilingPlatformOther.c +++ lib/profile/InstrProfilingPlatformOther.c @@ -12,63 +12,35 @@ #if !defined(__APPLE__) #include <stdlib.h> -static const __llvm_profile_data *DataFirst = NULL; -static const __llvm_profile_data *DataLast = NULL; -static const char *NamesFirst = NULL; -static const char *NamesLast = NULL; -static uint64_t *CountersFirst = NULL; -static uint64_t *CountersLast = NULL; - -/*! - * \brief Register an instrumented function. - * - * Calls to this are emitted by clang with -fprofile-instr-generate. Such - * calls are only required (and only emitted) on targets where we haven't - * implemented linker magic to find the bounds of the sections. - */ -__attribute__((visibility("hidden"))) -void __llvm_profile_register_function(void *Data_) { - /* TODO: Only emit this function if we can't use linker magic. */ - const __llvm_profile_data *Data = (__llvm_profile_data*)Data_; - if (!DataFirst) { - DataFirst = Data; - DataLast = Data + 1; - NamesFirst = Data->Name; - NamesLast = Data->Name + Data->NameSize; - CountersFirst = Data->Counters; - CountersLast = Data->Counters + Data->NumCounters; - return; - } - -#define UPDATE_FIRST(First, New) \ - First = New < First ? New : First - UPDATE_FIRST(DataFirst, Data); - UPDATE_FIRST(NamesFirst, Data->Name); - UPDATE_FIRST(CountersFirst, Data->Counters); -#undef UPDATE_FIRST - -#define UPDATE_LAST(Last, New) \ - Last = New > Last ? New : Last - UPDATE_LAST(DataLast, Data + 1); - UPDATE_LAST(NamesLast, Data->Name + Data->NameSize); - UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters); -#undef UPDATE_LAST -} +extern __llvm_profile_data __llvm_prf_data_start; +extern __llvm_profile_data __llvm_prf_data_end; +extern uint64_t __llvm_prf_cnts_start; +extern uint64_t __llvm_prf_cnts_end; +extern char __llvm_prf_names_start; +extern char __llvm_prf_names_end; __attribute__((visibility("hidden"))) const __llvm_profile_data *__llvm_profile_begin_data(void) { - return DataFirst; + return &__llvm_prf_data_start; } __attribute__((visibility("hidden"))) const __llvm_profile_data *__llvm_profile_end_data(void) { - return DataLast; + return &__llvm_prf_data_end; +} +__attribute__((visibility("hidden"))) const char *__llvm_profile_begin_names( + void) { + return &__llvm_prf_names_start; +} +__attribute__((visibility("hidden"))) const char *__llvm_profile_end_names( + void) { + return &__llvm_prf_names_end; +} +__attribute__((visibility("hidden"))) uint64_t *__llvm_profile_begin_counters( + void) { + return &__llvm_prf_cnts_start; +} +__attribute__((visibility("hidden"))) uint64_t *__llvm_profile_end_counters( + void) { + return &__llvm_prf_cnts_end; } -__attribute__((visibility("hidden"))) -const char *__llvm_profile_begin_names(void) { return NamesFirst; } -__attribute__((visibility("hidden"))) -const char *__llvm_profile_end_names(void) { return NamesLast; } -__attribute__((visibility("hidden"))) -uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } -__attribute__((visibility("hidden"))) -uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } #endif Index: lib/profile/CMakeLists.txt =================================================================== --- lib/profile/CMakeLists.txt +++ lib/profile/CMakeLists.txt @@ -24,6 +24,11 @@ CFLAGS -fPIC SOURCES ${PROFILE_SOURCES} PARENT_TARGET profile) + if(UNIX) + # Assume Linux + add_compiler_rt_resource_file(profile_x prf_data.x) + add_dependencies(profile profile_x) + endif() endif() add_dependencies(compiler-rt profile) Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -2402,83 +2402,12 @@ } } -// Until ARM libraries are build separately, we have them all in one library -static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, - const ArgList &Args) { - const llvm::Triple &Triple = TC.getTriple(); - bool IsWindows = Triple.isOSWindows(); - - if (Triple.isWindowsMSVCEnvironment() && TC.getArch() == llvm::Triple::x86) - return "i386"; - - if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) - return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) - ? "armhf" - : "arm"; - - return TC.getArchName(); -} - -static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) { - // The runtimes are located in the OS-specific resource directory. - SmallString<128> Res(TC.getDriver().ResourceDir); - const llvm::Triple &Triple = TC.getTriple(); - // TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected. - StringRef OSLibName = - (Triple.getOS() == llvm::Triple::FreeBSD) ? "freebsd" : TC.getOS(); - llvm::sys::path::append(Res, "lib", OSLibName); - return Res; -} - -SmallString<128> tools::getCompilerRT(const ToolChain &TC, const ArgList &Args, - StringRef Component, bool Shared) { - const char *Env = TC.getTriple().getEnvironment() == llvm::Triple::Android - ? "-android" - : ""; - - bool IsOSWindows = TC.getTriple().isOSWindows(); - bool IsITANMSVCWindows = TC.getTriple().isWindowsMSVCEnvironment() || - TC.getTriple().isWindowsItaniumEnvironment(); - StringRef Arch = getArchNameForCompilerRTLib(TC, Args); - const char *Prefix = IsITANMSVCWindows ? "" : "lib"; - const char *Suffix = - Shared ? (IsOSWindows ? ".dll" : ".so") : (IsITANMSVCWindows ? ".lib" : ".a"); - - SmallString<128> Path = getCompilerRTLibDir(TC); - llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + - Arch + Env + Suffix); - - return Path; -} - -static const char *getCompilerRTArgString(const ToolChain &TC, - const llvm::opt::ArgList &Args, - StringRef Component, - bool Shared = false) { - return Args.MakeArgString(getCompilerRT(TC, Args, Component, Shared)); -} - // This adds the static libclang_rt.builtins-arch.a directly to the command line // FIXME: Make sure we can also emit shared objects if they're requested // and available, check for possible errors, etc. static void addClangRT(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - CmdArgs.push_back(getCompilerRTArgString(TC, Args, "builtins")); -} - -static void addProfileRT(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - 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) || - Args.hasArg(options::OPT_coverage))) - return; - - CmdArgs.push_back(getCompilerRTArgString(TC, Args, "profile")); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); } namespace { @@ -2559,7 +2488,7 @@ // whole-archive. if (!IsShared) CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(getCompilerRTArgString(TC, Args, Sanitizer, IsShared)); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); if (!IsShared) CmdArgs.push_back("-no-whole-archive"); } @@ -2569,7 +2498,7 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { - SmallString<128> SanRT = getCompilerRT(TC, Args, Sanitizer); + SmallString<128> SanRT = TC.getCompilerRT(Args, Sanitizer); if (llvm::sys::fs::exists(SanRT + ".syms")) { CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); return true; @@ -7014,7 +6943,7 @@ } CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); @@ -7605,7 +7534,7 @@ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - addProfileRT(ToolChain, Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); @@ -7894,7 +7823,7 @@ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); @@ -8419,7 +8348,7 @@ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { @@ -8730,7 +8659,7 @@ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { @@ -8922,7 +8851,7 @@ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); @@ -9028,18 +8957,18 @@ "asan_dynamic", "asan_dynamic_runtime_thunk", }; for (const auto &Component : CompilerRTComponents) - CmdArgs.push_back(getCompilerRTArgString(TC, Args, Component)); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Component)); // Make sure the dynamic runtime thunk is not optimized out at link time // to ensure proper SEH handling. CmdArgs.push_back(Args.MakeArgString("-include:___asan_seh_interceptor")); } else if (DLL) { - CmdArgs.push_back(getCompilerRTArgString(TC, Args, "asan_dll_thunk")); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); } else { static const char *CompilerRTComponents[] = { "asan", "asan_cxx", }; for (const auto &Component : CompilerRTComponents) - CmdArgs.push_back(getCompilerRTArgString(TC, Args, Component)); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Component)); } } Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -275,9 +275,11 @@ /// Add any profiling runtime libraries that are needed. This is essentially a /// MachO specific version of addProfileRT in Tools.cpp. - virtual void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { + virtual bool addProfileRTLibs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override { // There aren't any profiling libs for embedded targets currently. + return false; } /// } @@ -378,7 +380,7 @@ return !isTargetIPhoneOS() || isIPhoneOSVersionLT(6, 0); } - void addProfileRTLibs(const llvm::opt::ArgList &Args, + bool addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; protected: @@ -526,6 +528,8 @@ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + bool addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; }; class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -298,7 +298,7 @@ } } -void Darwin::addProfileRTLibs(const ArgList &Args, +bool Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || @@ -308,15 +308,16 @@ Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage))) - return; + return false; // Select the appropriate runtime library for the target. if (isTargetIOSBased()) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a", /*AlwaysLink*/ true); else AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a", /*AlwaysLink*/ true); + return true; } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, @@ -2183,6 +2184,16 @@ CC1Args.push_back("-fuse-init-array"); } +bool Generic_ELF::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!ToolChain::addProfileRTLibs(Args, CmdArgs)) return false; + + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, "prf_data.x"); + CmdArgs.push_back(Args.MakeArgString(Path)); + return true; +} + /// Hexagon Toolchain std::string HexagonToolChain::GetGnuDir(const std::string &InstalledDir, Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -456,6 +456,78 @@ void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} +bool ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + 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) || + Args.hasArg(options::OPT_coverage))) + return false; + + CmdArgs.push_back(getCompilerRTArgString(Args, "profile")); + return true; +} + +StringRef ToolChain::getArchNameForCompilerRTLib( + const llvm::opt::ArgList &Args) const { + const llvm::Triple &Triple = getTriple(); + bool IsWindows = Triple.isOSWindows(); + + if (Triple.isWindowsMSVCEnvironment() && getArch() == llvm::Triple::x86) + return "i386"; + + if (getArch() == llvm::Triple::arm || getArch() == llvm::Triple::armeb) + return (tools::arm::getARMFloatABI(*this, Args) == + tools::arm::FloatABI::Hard && + !IsWindows) + ? "armhf" + : "arm"; + + return getArchName(); +} + +SmallString<128> ToolChain::getCompilerRTLibDir() const { + // The runtimes are located in the OS-specific resource directory. + SmallString<128> Res(getDriver().ResourceDir); + const llvm::Triple &Triple = getTriple(); + // TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected. + StringRef OSLibName = + (Triple.getOS() == llvm::Triple::FreeBSD) ? "freebsd" : getOS(); + llvm::sys::path::append(Res, "lib", OSLibName); + return Res; +} + +SmallString<128> ToolChain::getCompilerRT(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared) const { + const char *Env = + getTriple().getEnvironment() == llvm::Triple::Android ? "-android" : ""; + + bool IsOSWindows = getTriple().isOSWindows(); + bool IsITANMSVCWindows = getTriple().isWindowsMSVCEnvironment() || + getTriple().isWindowsItaniumEnvironment(); + StringRef Arch = getArchNameForCompilerRTLib(Args); + const char *Prefix = IsITANMSVCWindows ? "" : "lib"; + const char *Suffix = Shared ? (IsOSWindows ? ".dll" : ".so") + : (IsITANMSVCWindows ? ".lib" : ".a"); + + SmallString<128> Path = getCompilerRTLibDir(); + llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + + Arch + Env + Suffix); + + return Path; +} + +const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared) const { + return Args.MakeArgString(getCompilerRT(Args, Component, Shared)); +} + ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( const ArgList &Args) const { Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -609,13 +609,11 @@ if (TC.getTriple().isOSWindows() && needsUbsanRt()) { // Instruct the code generator to embed linker directives in the object file // that cause the required runtime libraries to be linked. - CmdArgs.push_back( - Args.MakeArgString("--dependent-lib=" + - tools::getCompilerRT(TC, Args, "ubsan_standalone"))); + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); if (types::isCXX(InputType)) CmdArgs.push_back(Args.MakeArgString( - "--dependent-lib=" + - tools::getCompilerRT(TC, Args, "ubsan_standalone_cxx"))); + "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); } } Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -96,6 +96,8 @@ virtual Tool *buildAssembler() const; virtual Tool *buildLinker() const; virtual Tool *getTool(Action::ActionClass AC) const; + SmallString<128> getCompilerRTLibDir() const; + StringRef getArchNameForCompilerRTLib(const llvm::opt::ArgList &Args) const; /// \name Utilities for implementing subclasses. ///@{ @@ -165,6 +167,13 @@ static std::pair<std::string, std::string> getTargetAndModeFromProgramName(StringRef ProgName); + /// Return link commmand line arguments for clang runtime libraries. + SmallString<128> getCompilerRT(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared = false) const; + const char *getCompilerRTArgString(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared = false) const; // Tool access. /// TranslateArgs - Create a new derived argument list for any argument @@ -364,6 +373,11 @@ AddFastMathRuntimeIfAvailable(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + /// addProfileRTLibs - When -fprofile-instr-profile is specified, add profile + /// runtime library, otherwise return false. + virtual bool addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// \brief Return sanitizers which are available in this toolchain. virtual SanitizerMask getSupportedSanitizers() const; }; Index: test/Instrumentation/InstrProfiling/platform.ll =================================================================== --- test/Instrumentation/InstrProfiling/platform.ll +++ test/Instrumentation/InstrProfiling/platform.ll @@ -23,7 +23,7 @@ ;; symbols by their sections. ; MACHO-NOT: define internal void @__llvm_profile_register_functions -; ELF: define internal void @__llvm_profile_register_functions +; ELF-NOT: define internal void @__llvm_profile_register_functions ; MACHO-NOT: define internal void @__llvm_profile_init -; ELF: define internal void @__llvm_profile_init +; ELF-NOT: define internal void @__llvm_profile_init Index: lib/Transforms/Instrumentation/InstrProfiling.cpp =================================================================== --- lib/Transforms/Instrumentation/InstrProfiling.cpp +++ lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -257,6 +257,9 @@ if (Triple(M->getTargetTriple()).isOSDarwin()) return; + // Use linker script magic to get data/cnts/name start/end. + if (Triple(M->getTargetTriple()).isOSLinux()) return; + // Construct the function. auto *VoidTy = Type::getVoidTy(M->getContext()); auto *VoidPtrTy = Type::getInt8PtrTy(M->getContext());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits