[PGO][AIX] Improve dummy var retention and allow -bcdtors:csect linking.
1) Use a static array of pointer to retain the dummy vars. 2) Associate liveness of the array with that of the runtime hook variable __llvm_profile_runtime. 3) Perform the runtime initialization through the runtime hook variable. 4) Preserve the runtime hook variable using the -u linker flag. Reviewed By: hubert.reinterpretcast Differential Revision: https://reviews.llvm.org/D136192
This commit is contained in:
parent
4fd2b49115
commit
461a1836d3
|
@ -13,6 +13,7 @@
|
||||||
#include "clang/Driver/Options.h"
|
#include "clang/Driver/Options.h"
|
||||||
#include "clang/Driver/SanitizerArgs.h"
|
#include "clang/Driver/SanitizerArgs.h"
|
||||||
#include "llvm/Option/ArgList.h"
|
#include "llvm/Option/ArgList.h"
|
||||||
|
#include "llvm/ProfileData/InstrProf.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
|
|
||||||
using AIX = clang::driver::toolchains::AIX;
|
using AIX = clang::driver::toolchains::AIX;
|
||||||
|
@ -348,6 +349,16 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
||||||
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
|
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
|
||||||
|
llvm::opt::ArgStringList &CmdArgs) const {
|
||||||
|
// Add linker option -u__llvm_profile_runtime to cause runtime
|
||||||
|
// initialization to occur.
|
||||||
|
if (needsProfileRT(Args))
|
||||||
|
CmdArgs.push_back(Args.MakeArgString(
|
||||||
|
Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
|
||||||
|
ToolChain::addProfileRTLibs(Args, CmdArgs);
|
||||||
|
}
|
||||||
|
|
||||||
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
|
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
|
||||||
return ToolChain::CST_Libcxx;
|
return ToolChain::CST_Libcxx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,9 @@ public:
|
||||||
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
||||||
llvm::opt::ArgStringList &CmdArgs) const override;
|
llvm::opt::ArgStringList &CmdArgs) const override;
|
||||||
|
|
||||||
|
void addProfileRTLibs(const llvm::opt::ArgList &Args,
|
||||||
|
llvm::opt::ArgStringList &CmdArgs) const override;
|
||||||
|
|
||||||
CXXStdlibType GetDefaultCXXStdlibType() const override;
|
CXXStdlibType GetDefaultCXXStdlibType() const override;
|
||||||
|
|
||||||
RuntimeLibType GetDefaultRuntimeLibType() const override;
|
RuntimeLibType GetDefaultRuntimeLibType() const override;
|
||||||
|
|
|
@ -250,23 +250,21 @@ void __llvm_profile_register_names_function(void *NamesStart,
|
||||||
// section exists. So for the scenario where the user objects have no such
|
// section exists. So for the scenario where the user objects have no such
|
||||||
// section (i.e. when they are compiled with -fno-profile-generate), we always
|
// section (i.e. when they are compiled with -fno-profile-generate), we always
|
||||||
// define these zero length variables in each of the above 4 sections.
|
// define these zero length variables in each of the above 4 sections.
|
||||||
COMPILER_RT_VISIBILITY int dummy_cnts[0] COMPILER_RT_SECTION(
|
static int dummy_cnts[0] COMPILER_RT_SECTION(
|
||||||
COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
|
COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
|
||||||
COMPILER_RT_VISIBILITY int dummy_data[0] COMPILER_RT_SECTION(
|
static int dummy_data[0] COMPILER_RT_SECTION(
|
||||||
COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
|
COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
|
||||||
COMPILER_RT_VISIBILITY const int dummy_name[0] COMPILER_RT_SECTION(
|
static const int dummy_name[0] COMPILER_RT_SECTION(
|
||||||
COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
|
COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
|
||||||
COMPILER_RT_VISIBILITY int dummy_vnds[0] COMPILER_RT_SECTION(
|
static int dummy_vnds[0] COMPILER_RT_SECTION(
|
||||||
COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
|
COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
|
||||||
|
|
||||||
// Create a fake reference to avoid GC'ing of the dummy variables by the linker.
|
// To avoid GC'ing of the dummy variables by the linker, reference them in an
|
||||||
// Ideally, we create a ".ref" of each variable inside the function
|
// array and reference the array in the runtime registration code
|
||||||
// __llvm_profile_begin_counters(), but there's no source level construct
|
// (InstrProfilingRuntime.cpp)
|
||||||
// that allows us to generate that.
|
COMPILER_RT_VISIBILITY
|
||||||
__attribute__((destructor)) void keep() {
|
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_data,
|
||||||
int volatile use = &dummy_cnts < &dummy_data && &dummy_name < &dummy_vnds;
|
(void *)&dummy_name, (void *)&dummy_vnds};
|
||||||
(void)use;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,19 +10,23 @@ extern "C" {
|
||||||
|
|
||||||
#include "InstrProfiling.h"
|
#include "InstrProfiling.h"
|
||||||
|
|
||||||
|
static int RegisterRuntime() {
|
||||||
|
__llvm_profile_initialize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _AIX
|
||||||
/* int __llvm_profile_runtime */
|
/* int __llvm_profile_runtime */
|
||||||
COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR;
|
COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR;
|
||||||
}
|
|
||||||
|
static int Registration = RegisterRuntime();
|
||||||
namespace {
|
#else
|
||||||
|
extern COMPILER_RT_VISIBILITY void *__llvm_profile_keep[];
|
||||||
class RegisterRuntime {
|
/* On AIX, when linking with -bcdtors:csect, the variable whose constructor does
|
||||||
public:
|
* the registration needs to be explicitly kept, hence we reuse the runtime hook
|
||||||
RegisterRuntime() {
|
* variable to do the registration since it'll be kept via the -u linker flag.
|
||||||
__llvm_profile_initialize();
|
* Create a volatile reference to __llvm_profile_keep to keep the array alive.*/
|
||||||
}
|
COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR =
|
||||||
};
|
((void)*(void *volatile *)__llvm_profile_keep, RegisterRuntime());
|
||||||
|
#endif
|
||||||
RegisterRuntime Registration;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
def getRoot(config):
|
||||||
|
if not config.parent:
|
||||||
|
return config
|
||||||
|
return getRoot(config.parent)
|
||||||
|
|
||||||
|
root = getRoot(config)
|
||||||
|
|
||||||
|
if root.host_os not in ['AIX']:
|
||||||
|
config.unsupported = True
|
|
@ -0,0 +1,14 @@
|
||||||
|
// RUN: split-file %s %t
|
||||||
|
// RUN: cd %t
|
||||||
|
//
|
||||||
|
// RUN: %clang_pgogen foo.c -c -o foo.o
|
||||||
|
// RUN: %clang_pgogen -shared foo.o -o libfoo.so -bexpall
|
||||||
|
// RUN: %clang_pgogen -L%t user.c libfoo.so -o user1
|
||||||
|
// RUN: ./user1
|
||||||
|
|
||||||
|
//--- foo.c
|
||||||
|
void foo() {}
|
||||||
|
|
||||||
|
//--- user.c
|
||||||
|
void foo();
|
||||||
|
int main() { foo(); }
|
|
@ -1199,7 +1199,7 @@ void InstrProfiling::emitRegistration() {
|
||||||
bool InstrProfiling::emitRuntimeHook() {
|
bool InstrProfiling::emitRuntimeHook() {
|
||||||
// We expect the linker to be invoked with -u<hook_var> flag for Linux
|
// We expect the linker to be invoked with -u<hook_var> flag for Linux
|
||||||
// in which case there is no need to emit the external variable.
|
// in which case there is no need to emit the external variable.
|
||||||
if (TT.isOSLinux())
|
if (TT.isOSLinux() || TT.isOSAIX())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If the module's provided its own runtime, we don't need to do anything.
|
// If the module's provided its own runtime, we don't need to do anything.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,DARWIN
|
; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,DARWIN
|
||||||
; RUN: opt < %s -mtriple=x86_64-linux-unknown -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,LINUX
|
; RUN: opt < %s -mtriple=x86_64-linux-unknown -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,LINUX
|
||||||
; RUN: opt < %s -mtriple=powerpc64-ibm-aix-xcoff -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,DARWIN
|
; RUN: opt < %s -mtriple=powerpc64-ibm-aix-xcoff -passes=instrprof -S | FileCheck %s -check-prefixes=ALL,LINUX
|
||||||
; ALL-NOT: @__profc
|
; ALL-NOT: @__profc
|
||||||
; ALL-NOT: @__profd
|
; ALL-NOT: @__profd
|
||||||
; DARWIN: @__llvm_profile_runtime
|
; DARWIN: @__llvm_profile_runtime
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
; MACHO: @__llvm_profile_runtime = external hidden global i32
|
; MACHO: @__llvm_profile_runtime = external hidden global i32
|
||||||
; ELF_GENERIC: @__llvm_profile_runtime = external hidden global i32
|
; ELF_GENERIC: @__llvm_profile_runtime = external hidden global i32
|
||||||
; ELF-NOT: @__llvm_profile_runtime = external global i32
|
; ELF-NOT: @__llvm_profile_runtime = external global i32
|
||||||
; XCOFF: @__llvm_profile_runtime = external hidden global i32
|
; XCOFF-NOT: @__llvm_profile_runtime = external hidden global i32
|
||||||
; COFF: @__llvm_profile_runtime = external hidden global i32
|
; COFF: @__llvm_profile_runtime = external hidden global i32
|
||||||
|
|
||||||
; ELF: $__profc_foo = comdat nodeduplicate
|
; ELF: $__profc_foo = comdat nodeduplicate
|
||||||
|
@ -101,7 +101,7 @@ declare void @llvm.instrprof.increment(ptr, i64, i32, i32)
|
||||||
; ELF_GENERIC: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime, ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern]
|
; ELF_GENERIC: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime, ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern]
|
||||||
; MACHO: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime_user, ptr @__profd_foo, {{.*}}
|
; MACHO: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime_user, ptr @__profd_foo, {{.*}}
|
||||||
; COFF: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime_user, ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern]
|
; COFF: @llvm.compiler.used = appending global [6 x ptr] [ptr @__llvm_profile_runtime_user, ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern]
|
||||||
; XCOFF: @llvm.used = appending global [7 x ptr] [ptr @__llvm_profile_runtime_user, ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern, ptr @__llvm_prf_nm]
|
; XCOFF: @llvm.used = appending global [6 x ptr] [ptr @__profd_foo, ptr @__profd_foo_weak, ptr @"__profd_linkage.ll:foo_internal", ptr @__profd_foo_inline, ptr @__profd_foo_extern, ptr @__llvm_prf_nm]
|
||||||
|
|
||||||
; MACHO: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} {
|
; MACHO: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} {
|
||||||
; MACHO: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
; MACHO: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
||||||
|
@ -112,10 +112,7 @@ declare void @llvm.instrprof.increment(ptr, i64, i32, i32)
|
||||||
; ELFRT-NOT: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
; ELFRT-NOT: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
||||||
; PS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} {
|
; PS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} {
|
||||||
; PS: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
; PS: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
||||||
; XCOFF: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} {
|
; XCOFF-NOT: define .* __llvm_profile_runtime_user
|
||||||
; XCOFF: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime
|
|
||||||
; XCOFF: ret i32 %[[REG]]
|
|
||||||
; XCOFF: }
|
|
||||||
|
|
||||||
; ELF_GENERIC: define internal void @__llvm_profile_register_functions() unnamed_addr {
|
; ELF_GENERIC: define internal void @__llvm_profile_register_functions() unnamed_addr {
|
||||||
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(ptr @__llvm_profile_runtime)
|
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(ptr @__llvm_profile_runtime)
|
||||||
|
|
Loading…
Reference in New Issue