-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[PGO] Initialize GCOV Writeout and Reset Functions in the Runtime on AIX #108570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-backend-powerpc Author: Qiongsi Wu (qiongsiwu) ChangesThis PR registers the writeout and reset functions for When registering such functions using global constructors in each module without The implementation adds a new global variable
are implemented to return the start and end address of this named section in the final binary, and they are used in function
(which is a constructor function in the runtime) so the runtime knows the addresses of all the One noticeable implementation detail relevant to AIX is that to preserve the Patch is 26.57 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108570.diff 14 Files Affected:
diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c
index df2cabf28693a3..1aca3b1bfa5b59 100644
--- a/clang/test/CodeGen/attr-function-return.c
+++ b/clang/test/CodeGen/attr-function-return.c
@@ -9,7 +9,7 @@
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-EXTERN
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
// RUN: -mfunction-return=thunk-extern -coverage-data-file=/dev/null \
-// RUN: | FileCheck %s --check-prefix=CHECK-GCOV
+// RUN: | FileCheck %s --check-prefixes=CHECK-GCOV
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
// RUN: -mfunction-return=thunk-extern -fsanitize=address \
// RUN: | FileCheck %s --check-prefix=CHECK-ASAN
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index d7994bab35d81a..30c59d58380def 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -3,12 +3,18 @@
/// 4.7 enables cfg_checksum.
/// 4.8 (default, compatible with gcov 7) emits the exit block the second.
// RUN: rm -rf %t && mkdir %t && cd %t
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,304 %s
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,407 %s
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,408 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,304 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,407 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,408 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,304 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,407 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,408 %s
// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-notes-file=aaa.gcno -coverage-data-file=bbb.gcda -debug-info-kind=limited -dwarf-version=4 %s -o - | FileCheck %s --check-prefix GCOV_FILE_INFO
@@ -23,6 +29,9 @@
// NEWPM-O3: Running pass: ForceFunctionAttrsPass
// NEWPM-O3: Running pass: GCOVProfilerPass
+// Check for gcov initialization function pointers.
+// CHECK-XCOFF: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
int test1(int a) {
switch (a % 2) {
case 0:
@@ -52,7 +61,7 @@ int test2(int b) {
// Check that the noredzone flag is set on the generated functions.
// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]]
-// CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
+// CHECK-ELF: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }
diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc
index b9df3266fbcf8f..591fc1401e1aab 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -303,6 +303,18 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
+/* COVINIT_FUNC start */
+#ifndef COVINIT_FUNC
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), WriteoutFunction, \
+ WriteoutF)
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), ResetFunction, \
+ ResetF)
+#undef COVINIT_FUNC
+/* COVINIT_FUNC end */
#ifdef INSTR_PROF_SECT_ENTRY
#define INSTR_PROF_DATA_DEFINED
@@ -345,6 +357,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covinit, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON), \
+ INSTR_PROF_COVINIT_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -761,6 +776,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
+#define INSTR_PROF_COVINIT_COMMON __llvm_covinit
+
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
*/
@@ -781,6 +798,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
+// TODO: Placeholder for Windows. We need to revise when we upstream this.
+#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
+
#ifdef _WIN32
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
@@ -800,6 +820,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_COVINIT_COFF
#else
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
@@ -821,6 +842,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON)
#endif
#define INSTR_PROF_ORDERFILE_BUFFER_NAME _llvm_order_file_buffer
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
index d6e2175169e4a5..452a62fcc9d21e 100644
--- a/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -624,6 +624,25 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr rfn) {
}
}
+#if defined(_AIX)
+COMPILER_RT_VISIBILITY __attribute__((constructor)) void
+__llvm_profile_gcov_initialize() {
+ const __llvm_gcov_init_func_struct *InitFuncStart =
+ __llvm_profile_begin_covinit();
+ const __llvm_gcov_init_func_struct *InitFuncEnd =
+ __llvm_profile_end_covinit();
+
+ for (const __llvm_gcov_init_func_struct *Ptr = InitFuncStart;
+ Ptr != InitFuncEnd; ++Ptr) {
+ fn_ptr wfn = (fn_ptr)Ptr->WriteoutFunction;
+ fn_ptr rfn = (fn_ptr)Ptr->ResetFunction;
+ if (!(wfn && rfn))
+ continue;
+ llvm_gcov_init(wfn, rfn);
+ }
+}
+#endif
+
void __gcov_dump(void) {
for (struct fn_node *f = writeout_fn_list.head; f; f = f->next)
f->fn();
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 6906d52eacaf1b..a62eca738327a9 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -54,6 +54,12 @@ typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) VTableProfData {
#include "profile/InstrProfData.inc"
} VTableProfData;
+typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT)
+ __llvm_gcov_init_func_struct {
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer) Type Name;
+#include "profile/InstrProfData.inc"
+} __llvm_gcov_init_func_struct;
+
/*!
* \brief Return 1 if profile counters are continuously synced to the raw
* profile via an mmap(). This is in contrast to the default mode, in which
@@ -208,6 +214,9 @@ void __llvm_profile_initialize_file(void);
/*! \brief Initialize the profile runtime. */
void __llvm_profile_initialize(void);
+/*! \brief Initialize the gcov profile runtime. */
+void __llvm_profile_gcov_initialize(void);
+
/*!
* \brief Return path prefix (excluding the base filename) of the profile data.
* This is useful for users using \c -fprofile-generate=./path_prefix who do
@@ -324,4 +333,6 @@ COMPILER_RT_VISIBILITY extern uint64_t
*/
extern char INSTR_PROF_PROFILE_NAME_VAR[1]; /* __llvm_profile_filename. */
+const __llvm_gcov_init_func_struct *__llvm_profile_begin_covinit();
+const __llvm_gcov_init_func_struct *__llvm_profile_end_covinit();
#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
index b9d51b698b414f..651f8785d0b940 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
@@ -202,6 +202,8 @@ static int dummy_vname[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);
static int dummy_vtab[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);
+static int dummy_covinit_funcs[0] COMPILER_RT_SECTION(
+ COMPILER_RT_SEG INSTR_PROF_COVINIT_SECT_NAME);
// To avoid GC'ing of the dummy variables by the linker, reference them in an
// array and reference the array in the runtime registration code
@@ -214,7 +216,8 @@ COMPILER_RT_VISIBILITY
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
(void *)&dummy_data, (void *)&dummy_name,
(void *)&dummy_vnds, (void *)&dummy_orderfile,
- (void *)&dummy_vname, (void *)&dummy_vtab};
+ (void *)&dummy_vname, (void *)&dummy_vtab,
+ (void *)&dummy_covinit_funcs};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
index b766436497b741..4c22bf42eac569 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -35,6 +35,8 @@
#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON)
#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON)
+#define PROF_COVINIT_START INSTR_PROF_SECT_START(INSTR_PROF_COVINIT_COMMON)
+#define PROF_COVINIT_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_COVINIT_COMMON)
/* Declare section start and stop symbols for various sections
* generated by compiler instrumentation.
@@ -56,6 +58,10 @@ extern char PROF_NAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
+extern __llvm_gcov_init_func_struct PROF_COVINIT_START COMPILER_RT_VISIBILITY
+ COMPILER_RT_WEAK;
+extern __llvm_gcov_init_func_struct PROF_COVINIT_STOP COMPILER_RT_VISIBILITY
+ COMPILER_RT_WEAK;
COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_begin_data(void) {
@@ -110,6 +116,16 @@ COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) {
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START;
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP;
+COMPILER_RT_VISIBILITY const __llvm_gcov_init_func_struct *
+__llvm_profile_begin_covinit() {
+ return &PROF_COVINIT_START;
+}
+
+COMPILER_RT_VISIBILITY const __llvm_gcov_init_func_struct *
+__llvm_profile_end_covinit() {
+ return &PROF_COVINIT_STOP;
+}
+
#ifdef NT_GNU_BUILD_ID
static size_t RoundUp(size_t size, size_t align) {
return (size + align - 1) & ~(align - 1);
diff --git a/compiler-rt/test/profile/AIX/gcov-undef-sym.test b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
new file mode 100644
index 00000000000000..e377b321ca66cd
--- /dev/null
+++ b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
@@ -0,0 +1,52 @@
+// The undefined symbol should not cause link errors, and we should
+// obtain the expected coverage report.
+
+// Test the --coverage option.
+RUN: rm -rf %t0 && split-file %s %t0 && cd %t0
+RUN: %clang bar.c main.c undef.c --coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang main.o -L. -lfoo --coverage -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+// Test the pgogen -fprofile-arcs -ftest-coverage option combination.
+RUN: rm -rf %t1 && split-file %s %t1 && cd %t1
+RUN: %clang_pgogen bar.c main.c undef.c -fprofile-arcs -ftest-coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang_pgogen main.o -L. -lfoo -fprofile-generate -fprofile-arcs -ftest-coverage -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+// Test the pgogen -Wl,-bcdtors:mbr option combination.
+RUN: rm -rf %t2 && split-file %s %t2 && cd %t2
+RUN: %clang_pgogen bar.c main.c undef.c -fprofile-arcs -ftest-coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang_pgogen main.o -L. -lfoo -fprofile-generate -fprofile-arcs -ftest-coverage -Wl,-bcdtors:mbr -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+MAIN: 1: 2:int main() {
+MAIN: 1: 3: return bar();
+BAR: 1: 1:int bar() {
+BAR: 1: 2: return 0;
+
+//--- main.c
+int bar();
+int main() {
+ return bar();
+}
+
+
+//--- bar.c
+int bar() {
+ return 0;
+}
+
+//--- undef.c
+void undef_func();
+void foo() {
+ undef_func();
+}
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index b9df3266fbcf8f..591fc1401e1aab 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -303,6 +303,18 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
+/* COVINIT_FUNC start */
+#ifndef COVINIT_FUNC
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), WriteoutFunction, \
+ WriteoutF)
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), ResetFunction, \
+ ResetF)
+#undef COVINIT_FUNC
+/* COVINIT_FUNC end */
#ifdef INSTR_PROF_SECT_ENTRY
#define INSTR_PROF_DATA_DEFINED
@@ -345,6 +357,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covinit, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON), \
+ INSTR_PROF_COVINIT_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -761,6 +776,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
+#define INSTR_PROF_COVINIT_COMMON __llvm_covinit
+
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
*/
@@ -781,6 +798,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
+// TODO: Placeholder for Windows. We need to revise when we upstream this.
+#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
+
#ifdef _WIN32
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
@@ -800,6 +820,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_COVINIT_COFF
#else
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
@@ -821,6 +842,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON)
#endif
#define INSTR_PROF_ORDERFILE_BUFFER_NAME _llvm_order_file_buffer
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index dcde86388dcd9d..3251340aa67a6a 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -290,6 +290,8 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
void emitPGORefs(Module &M);
+ void emitGCOVRefs();
+
void emitEndOfAsmFile(Module &) override;
void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override;
@@ -2962,6 +2964,26 @@ void PPCAIXAsmPrinter::emitPGORefs(Module &M) {
}
}
+void PPCAIXAsmPrinter::emitGCOVRefs() {
+ if (!OutContext.hasXCOFFSection(
+ "__llvm_gcov_ctr_section",
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD)))
+ return;
+
+ MCSection *CtrSection = OutContext.getXCOFFSection(
+ "__llvm_gcov_ctr_section", SectionKind::getData(),
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD),
+ /*MultiSymbolsAllowed*/ true);
+
+ OutStreamer->switchSection(CtrSection);
+ if (OutContext.hasXCOFFSection(
+ "__llvm_covinit",
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) {
+ MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_covinit[RW]");
+ OutStreamer->emitXCOFFRefDirective(S);
+ }
+}
+
void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
// If there are no functions and there are no toc-data definitions in this
// module, we will never need to reference the TOC base.
@@ -2969,6 +2991,7 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
return;
emitPGORefs(M);
+ emitGCOVRefs();
// Switch to section to emit TOC base.
OutStreamer->switchSection(getObjFileLowering().getTOCBaseSection());
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index c7f6f2a43c17f5..4a399ad438215a 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -29,6 +29,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -121,8 +122,11 @@ class GCOVProfiler {
Function *createInternalFunction(FunctionType *FTy, StringRef Name,
StringRef MangledType = "");
+
void emitGlobalConstructor(
SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
+ void emitModuleInitFunctionPtrs(
+ SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
bool isFunctionInstrumented(const Function &F);
std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
@@ -914,6 +918,7 @@ bool GCOVProfiler::emitProfileNotes(
GlobalVariable *Counters = new GlobalVariable(
*M, Co...
[truncated]
|
@llvm/pr-subscribers-clang Author: Qiongsi Wu (qiongsiwu) ChangesThis PR registers the writeout and reset functions for When registering such functions using global constructors in each module without The implementation adds a new global variable
are implemented to return the start and end address of this named section in the final binary, and they are used in function
(which is a constructor function in the runtime) so the runtime knows the addresses of all the One noticeable implementation detail relevant to AIX is that to preserve the Patch is 26.57 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108570.diff 14 Files Affected:
diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c
index df2cabf28693a3..1aca3b1bfa5b59 100644
--- a/clang/test/CodeGen/attr-function-return.c
+++ b/clang/test/CodeGen/attr-function-return.c
@@ -9,7 +9,7 @@
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-EXTERN
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
// RUN: -mfunction-return=thunk-extern -coverage-data-file=/dev/null \
-// RUN: | FileCheck %s --check-prefix=CHECK-GCOV
+// RUN: | FileCheck %s --check-prefixes=CHECK-GCOV
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
// RUN: -mfunction-return=thunk-extern -fsanitize=address \
// RUN: | FileCheck %s --check-prefix=CHECK-ASAN
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index d7994bab35d81a..30c59d58380def 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -3,12 +3,18 @@
/// 4.7 enables cfg_checksum.
/// 4.8 (default, compatible with gcov 7) emits the exit block the second.
// RUN: rm -rf %t && mkdir %t && cd %t
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,304 %s
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,407 %s
-// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
-// RUN: FileCheck --check-prefixes=CHECK,408 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,304 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,407 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-ELF,408 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='304*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,304 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null -coverage-version='407*' %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,407 %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix -emit-llvm -disable-red-zone -coverage-data-file=/dev/null %s -o - | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK-XCOFF,408 %s
// RUN: %clang_cc1 -emit-llvm -disable-red-zone -coverage-notes-file=aaa.gcno -coverage-data-file=bbb.gcda -debug-info-kind=limited -dwarf-version=4 %s -o - | FileCheck %s --check-prefix GCOV_FILE_INFO
@@ -23,6 +29,9 @@
// NEWPM-O3: Running pass: ForceFunctionAttrsPass
// NEWPM-O3: Running pass: GCOVProfilerPass
+// Check for gcov initialization function pointers.
+// CHECK-XCOFF: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
int test1(int a) {
switch (a % 2) {
case 0:
@@ -52,7 +61,7 @@ int test2(int b) {
// Check that the noredzone flag is set on the generated functions.
// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]]
-// CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
+// CHECK-ELF: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }
diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc
index b9df3266fbcf8f..591fc1401e1aab 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -303,6 +303,18 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
+/* COVINIT_FUNC start */
+#ifndef COVINIT_FUNC
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), WriteoutFunction, \
+ WriteoutF)
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), ResetFunction, \
+ ResetF)
+#undef COVINIT_FUNC
+/* COVINIT_FUNC end */
#ifdef INSTR_PROF_SECT_ENTRY
#define INSTR_PROF_DATA_DEFINED
@@ -345,6 +357,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covinit, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON), \
+ INSTR_PROF_COVINIT_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -761,6 +776,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
+#define INSTR_PROF_COVINIT_COMMON __llvm_covinit
+
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
*/
@@ -781,6 +798,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
+// TODO: Placeholder for Windows. We need to revise when we upstream this.
+#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
+
#ifdef _WIN32
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
@@ -800,6 +820,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_COVINIT_COFF
#else
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
@@ -821,6 +842,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON)
#endif
#define INSTR_PROF_ORDERFILE_BUFFER_NAME _llvm_order_file_buffer
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
index d6e2175169e4a5..452a62fcc9d21e 100644
--- a/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -624,6 +624,25 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr rfn) {
}
}
+#if defined(_AIX)
+COMPILER_RT_VISIBILITY __attribute__((constructor)) void
+__llvm_profile_gcov_initialize() {
+ const __llvm_gcov_init_func_struct *InitFuncStart =
+ __llvm_profile_begin_covinit();
+ const __llvm_gcov_init_func_struct *InitFuncEnd =
+ __llvm_profile_end_covinit();
+
+ for (const __llvm_gcov_init_func_struct *Ptr = InitFuncStart;
+ Ptr != InitFuncEnd; ++Ptr) {
+ fn_ptr wfn = (fn_ptr)Ptr->WriteoutFunction;
+ fn_ptr rfn = (fn_ptr)Ptr->ResetFunction;
+ if (!(wfn && rfn))
+ continue;
+ llvm_gcov_init(wfn, rfn);
+ }
+}
+#endif
+
void __gcov_dump(void) {
for (struct fn_node *f = writeout_fn_list.head; f; f = f->next)
f->fn();
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 6906d52eacaf1b..a62eca738327a9 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -54,6 +54,12 @@ typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) VTableProfData {
#include "profile/InstrProfData.inc"
} VTableProfData;
+typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT)
+ __llvm_gcov_init_func_struct {
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer) Type Name;
+#include "profile/InstrProfData.inc"
+} __llvm_gcov_init_func_struct;
+
/*!
* \brief Return 1 if profile counters are continuously synced to the raw
* profile via an mmap(). This is in contrast to the default mode, in which
@@ -208,6 +214,9 @@ void __llvm_profile_initialize_file(void);
/*! \brief Initialize the profile runtime. */
void __llvm_profile_initialize(void);
+/*! \brief Initialize the gcov profile runtime. */
+void __llvm_profile_gcov_initialize(void);
+
/*!
* \brief Return path prefix (excluding the base filename) of the profile data.
* This is useful for users using \c -fprofile-generate=./path_prefix who do
@@ -324,4 +333,6 @@ COMPILER_RT_VISIBILITY extern uint64_t
*/
extern char INSTR_PROF_PROFILE_NAME_VAR[1]; /* __llvm_profile_filename. */
+const __llvm_gcov_init_func_struct *__llvm_profile_begin_covinit();
+const __llvm_gcov_init_func_struct *__llvm_profile_end_covinit();
#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
index b9d51b698b414f..651f8785d0b940 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
@@ -202,6 +202,8 @@ static int dummy_vname[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);
static int dummy_vtab[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);
+static int dummy_covinit_funcs[0] COMPILER_RT_SECTION(
+ COMPILER_RT_SEG INSTR_PROF_COVINIT_SECT_NAME);
// To avoid GC'ing of the dummy variables by the linker, reference them in an
// array and reference the array in the runtime registration code
@@ -214,7 +216,8 @@ COMPILER_RT_VISIBILITY
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
(void *)&dummy_data, (void *)&dummy_name,
(void *)&dummy_vnds, (void *)&dummy_orderfile,
- (void *)&dummy_vname, (void *)&dummy_vtab};
+ (void *)&dummy_vname, (void *)&dummy_vtab,
+ (void *)&dummy_covinit_funcs};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
index b766436497b741..4c22bf42eac569 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -35,6 +35,8 @@
#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON)
#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON)
+#define PROF_COVINIT_START INSTR_PROF_SECT_START(INSTR_PROF_COVINIT_COMMON)
+#define PROF_COVINIT_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_COVINIT_COMMON)
/* Declare section start and stop symbols for various sections
* generated by compiler instrumentation.
@@ -56,6 +58,10 @@ extern char PROF_NAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
+extern __llvm_gcov_init_func_struct PROF_COVINIT_START COMPILER_RT_VISIBILITY
+ COMPILER_RT_WEAK;
+extern __llvm_gcov_init_func_struct PROF_COVINIT_STOP COMPILER_RT_VISIBILITY
+ COMPILER_RT_WEAK;
COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_begin_data(void) {
@@ -110,6 +116,16 @@ COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) {
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START;
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP;
+COMPILER_RT_VISIBILITY const __llvm_gcov_init_func_struct *
+__llvm_profile_begin_covinit() {
+ return &PROF_COVINIT_START;
+}
+
+COMPILER_RT_VISIBILITY const __llvm_gcov_init_func_struct *
+__llvm_profile_end_covinit() {
+ return &PROF_COVINIT_STOP;
+}
+
#ifdef NT_GNU_BUILD_ID
static size_t RoundUp(size_t size, size_t align) {
return (size + align - 1) & ~(align - 1);
diff --git a/compiler-rt/test/profile/AIX/gcov-undef-sym.test b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
new file mode 100644
index 00000000000000..e377b321ca66cd
--- /dev/null
+++ b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
@@ -0,0 +1,52 @@
+// The undefined symbol should not cause link errors, and we should
+// obtain the expected coverage report.
+
+// Test the --coverage option.
+RUN: rm -rf %t0 && split-file %s %t0 && cd %t0
+RUN: %clang bar.c main.c undef.c --coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang main.o -L. -lfoo --coverage -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+// Test the pgogen -fprofile-arcs -ftest-coverage option combination.
+RUN: rm -rf %t1 && split-file %s %t1 && cd %t1
+RUN: %clang_pgogen bar.c main.c undef.c -fprofile-arcs -ftest-coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang_pgogen main.o -L. -lfoo -fprofile-generate -fprofile-arcs -ftest-coverage -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+// Test the pgogen -Wl,-bcdtors:mbr option combination.
+RUN: rm -rf %t2 && split-file %s %t2 && cd %t2
+RUN: %clang_pgogen bar.c main.c undef.c -fprofile-arcs -ftest-coverage -c
+RUN: ar -X32_64 -rv libfoo.a undef.o bar.o
+RUN: %clang_pgogen main.o -L. -lfoo -fprofile-generate -fprofile-arcs -ftest-coverage -Wl,-bcdtors:mbr -o main.exe
+RUN: main.exe
+RUN: llvm-cov gcov -t main.gcda | FileCheck --check-prefix=MAIN %s
+RUN: llvm-cov gcov -t bar.gcda | FileCheck --check-prefix=BAR %s
+
+MAIN: 1: 2:int main() {
+MAIN: 1: 3: return bar();
+BAR: 1: 1:int bar() {
+BAR: 1: 2: return 0;
+
+//--- main.c
+int bar();
+int main() {
+ return bar();
+}
+
+
+//--- bar.c
+int bar() {
+ return 0;
+}
+
+//--- undef.c
+void undef_func();
+void foo() {
+ undef_func();
+}
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index b9df3266fbcf8f..591fc1401e1aab 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -303,6 +303,18 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
+/* COVINIT_FUNC start */
+#ifndef COVINIT_FUNC
+#define COVINIT_FUNC(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), WriteoutFunction, \
+ WriteoutF)
+COVINIT_FUNC(IntPtrT, llvm::PointerType::getUnqual(Ctx), ResetFunction, \
+ ResetF)
+#undef COVINIT_FUNC
+/* COVINIT_FUNC end */
#ifdef INSTR_PROF_SECT_ENTRY
#define INSTR_PROF_DATA_DEFINED
@@ -345,6 +357,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_covinit, \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON), \
+ INSTR_PROF_COVINIT_COFF, "__LLVM_COV,")
#undef INSTR_PROF_SECT_ENTRY
#endif
@@ -761,6 +776,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
+#define INSTR_PROF_COVINIT_COMMON __llvm_covinit
+
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
*/
@@ -781,6 +798,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
+// TODO: Placeholder for Windows. We need to revise when we upstream this.
+#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
+
#ifdef _WIN32
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
@@ -800,6 +820,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_COVINIT_COFF
#else
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
@@ -821,6 +842,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
+#define INSTR_PROF_COVINIT_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVINIT_COMMON)
#endif
#define INSTR_PROF_ORDERFILE_BUFFER_NAME _llvm_order_file_buffer
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index dcde86388dcd9d..3251340aa67a6a 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -290,6 +290,8 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
void emitPGORefs(Module &M);
+ void emitGCOVRefs();
+
void emitEndOfAsmFile(Module &) override;
void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override;
@@ -2962,6 +2964,26 @@ void PPCAIXAsmPrinter::emitPGORefs(Module &M) {
}
}
+void PPCAIXAsmPrinter::emitGCOVRefs() {
+ if (!OutContext.hasXCOFFSection(
+ "__llvm_gcov_ctr_section",
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD)))
+ return;
+
+ MCSection *CtrSection = OutContext.getXCOFFSection(
+ "__llvm_gcov_ctr_section", SectionKind::getData(),
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD),
+ /*MultiSymbolsAllowed*/ true);
+
+ OutStreamer->switchSection(CtrSection);
+ if (OutContext.hasXCOFFSection(
+ "__llvm_covinit",
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) {
+ MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_covinit[RW]");
+ OutStreamer->emitXCOFFRefDirective(S);
+ }
+}
+
void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
// If there are no functions and there are no toc-data definitions in this
// module, we will never need to reference the TOC base.
@@ -2969,6 +2991,7 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
return;
emitPGORefs(M);
+ emitGCOVRefs();
// Switch to section to emit TOC base.
OutStreamer->switchSection(getObjFileLowering().getTOCBaseSection());
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index c7f6f2a43c17f5..4a399ad438215a 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -29,6 +29,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -121,8 +122,11 @@ class GCOVProfiler {
Function *createInternalFunction(FunctionType *FTy, StringRef Name,
StringRef MangledType = "");
+
void emitGlobalConstructor(
SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
+ void emitModuleInitFunctionPtrs(
+ SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
bool isFunctionInstrumented(const Function &F);
std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
@@ -914,6 +918,7 @@ bool GCOVProfiler::emitProfileNotes(
GlobalVariable *Counters = new GlobalVariable(
*M, Co...
[truncated]
|
I would like to get input from the community if it is a good idea to use this initialization mechanism on more platforms, such as on Linux/macOS. If it is advisable on more platforms, I will revise this PR so that we can perform the initialization in the runtime on as many platforms as possible. Thanks so much! |
You can test this locally with the following command:git-clang-format --diff 8625eb0b87c86d3ef42a365d7593eed664b379e8 426caab4c0365d5754c2ab876d7544356cdb2a6f --extensions c,cpp,h,inc -- clang/test/CodeGen/code-coverage.c compiler-rt/include/profile/InstrProfData.inc compiler-rt/lib/profile/GCDAProfiling.c compiler-rt/lib/profile/InstrProfiling.h compiler-rt/lib/profile/InstrProfilingPlatformAIX.c compiler-rt/lib/profile/InstrProfilingPlatformLinux.c llvm/include/llvm/ProfileData/InstrProfData.inc llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp View the diff from clang-format here.diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
index 651f8785d0..1c883f747b 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
@@ -213,11 +213,10 @@ static int dummy_covinit_funcs[0] COMPILER_RT_SECTION(
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
COMPILER_RT_VISIBILITY
-void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
- (void *)&dummy_data, (void *)&dummy_name,
- (void *)&dummy_vnds, (void *)&dummy_orderfile,
- (void *)&dummy_vname, (void *)&dummy_vtab,
- (void *)&dummy_covinit_funcs};
+void *__llvm_profile_keep[] = {
+ (void *)&dummy_cnts, (void *)&dummy_bits, (void *)&dummy_data,
+ (void *)&dummy_name, (void *)&dummy_vnds, (void *)&dummy_orderfile,
+ (void *)&dummy_vname, (void *)&dummy_vtab, (void *)&dummy_covinit_funcs};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|
Gentle ping for comments/reviews. @MaskRay @petrhosek @rorth . Thanks so much! |
I've now tested the patch on both |
Gentle ping for review @MaskRay @petrhosek . Could you recommend some reviewers so I can get more comments? Thanks! |
Ping for review! @MaskRay @petrhosek . Thanks so much! |
@hubert-reinterpretcast and @w2yehia could you take a look at this PR? We can land this PR if you both are OK with it. Currently, the PR only impacts AIX. Thanks so much! |
Thanks so much @hubert-reinterpretcast for the detailed review! All existing comments are now addressed. |
; CHECK: __llvm_gcov_ctr.1: | ||
; CHECK-NEXT: .extern .llvm_gcda_start_file[PR] | ||
; CHECK-NEXT: .extern .llvm_gcda_emit_function[PR] | ||
; CHECK-NEXT: .extern .llvm_gcda_emit_arcs[PR] | ||
; CHECK-NEXT: .extern .llvm_gcda_summary_info[PR] | ||
; CHECK-NEXT: .extern .llvm_gcda_end_file[PR] | ||
; CHECK-RW-NEXT: .ref __llvm_covinit[RW] | ||
; CHECK-RO-NEXT: .ref __llvm_covinit[RO] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems exceedingly weird. Why would we generate a label for __llvm_gcov_ctr.1:
and not specify the space it needs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I think this is because of the global merge that happens in llc
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I think this is because of the global merge that happens in llc.
Okay. We're seeing an existing bug here then. I'll see about getting an issue opened.
@@ -914,6 +918,9 @@ bool GCOVProfiler::emitProfileNotes( | |||
GlobalVariable *Counters = new GlobalVariable( | |||
*M, CounterTy, false, GlobalValue::InternalLinkage, | |||
Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); | |||
const llvm::Triple &Triple = llvm::Triple(M->getTargetTriple()); | |||
if (Triple.getObjectFormat() == llvm::Triple::XCOFF) | |||
Counters->setSection("__llvm_gcov_ctr_section"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest moving the .ref
generation to be from each GCOV-profiled function in the module instead of making this change. This change modifies the counters from being BSS in XCOFF to non-BSS (therefore increasing program load costs).
Not an impediment to landing this patch though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with minor comment; thanks!
We prefer to keep the formatting in this particular file. I am merging this PR. Thanks so much Hubert @hubert-reinterpretcast for the reviews and @rorth for testing things out! |
This PR registers the writeout and reset functions for
gcov
for all modules in the PGO runtime, instead of registering themusing global constructors in each module. The change is made for AIX only, but the same mechanism works on Linux on Power.
When registering such functions using global constructors in each module without
-ffunction-sections
, the AIX linker cannot garbage collect unused undefined symbols, because such symbols are grouped in the same section as the__sinit
symbol. Keeping such undefined symbols causes link errors (see test case https://github.com/llvm/llvm-project/pull/108570/files#diff-500a7e1ba871e1b6b61b523700d5e30987900002add306e1b5e4972cf6d5a4f1R1 for this scenario). This PR implements the initialization in the runtime, hence avoiding introducing__sinit
into each module.The implementation adds a new global variable
__llvm_covinit_functions
to each module. This new global variable contains the function pointers to theWriteout
andReset
functions.__llvm_covinit_functions
's section is the named section__llvm_covinit
. The linker will aggregate all the__llvm_covinit
sections from each moduleto form one single named section in the final binary. The pair of functions
are implemented to return the start and end address of this named section in the final binary, and they are used in function
(which is a constructor function in the runtime) so the runtime knows the addresses of all the
Writeout
andReset
functions from all the modules.One noticeable implementation detail relevant to AIX is that to preserve the
__llvm_covinit
from the linker's garbage collection, a.ref
pseudo instruction is inserted into them, referring to the section that contains the__llvm_gcov_ctr
variables, which are used in the instrumented code. The__llvm_gcov_ctr
variables did not belong to named sections before, but this PR added them to the__llvm_gcov_ctr_section
named section, so we can add a.ref
pseudo instruction that refers to them in the__llvm_covinit
section.