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 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: 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: 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/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,7 +308,7 @@ 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()) @@ -317,6 +317,7 @@ 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/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(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(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(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(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/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()); 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/profile/InstrProfilingPlatformOther.c =================================================================== --- lib/profile/InstrProfilingPlatformOther.c +++ lib/profile/InstrProfilingPlatformOther.c @@ -12,63 +12,35 @@ #if !defined(__APPLE__) #include -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/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: 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