[clang] [compiler-rt] [llvm] [PGO] Initialize GOV Writeout and Reset Functions in the Runtime on AIX (PR #108570)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 16 06:16:01 PDT 2024
https://github.com/qiongsiwu updated https://github.com/llvm/llvm-project/pull/108570
>From e1b5e886f3f7642ec691a08378a1f2cdc9e2465f Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Wed, 11 Sep 2024 14:56:58 -0400
Subject: [PATCH 1/3] Initial commit.
---
clang/test/CodeGen/attr-function-return.c | 5 +-
clang/test/CodeGen/code-coverage.c | 5 +-
clang/test/CodeGen/coverage-target-attr.c | 5 +-
compiler-rt/include/profile/InstrProfData.inc | 22 ++++++++
compiler-rt/lib/profile/GCDAProfiling.c | 17 ++++++
compiler-rt/lib/profile/InstrProfiling.h | 11 ++++
.../lib/profile/InstrProfilingPlatformAIX.c | 5 +-
.../lib/profile/InstrProfilingPlatformLinux.c | 16 ++++++
.../test/profile/AIX/gcov-undef-sym.test | 52 +++++++++++++++++++
.../llvm/ProfileData/InstrProfData.inc | 22 ++++++++
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 23 ++++++++
.../Instrumentation/GCOVProfiling.cpp | 48 ++++++++++-------
.../GCOVProfiling/kcfi-normalize.ll | 7 +--
llvm/test/Transforms/GCOVProfiling/kcfi.ll | 7 +--
.../Transforms/GCOVProfiling/module-flags.ll | 4 +-
15 files changed, 218 insertions(+), 31 deletions(-)
create mode 100644 compiler-rt/test/profile/AIX/gcov-undef-sym.test
diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c
index df2cabf28693a3..9c5cbca5640843 100644
--- a/clang/test/CodeGen/attr-function-return.c
+++ b/clang/test/CodeGen/attr-function-return.c
@@ -17,6 +17,9 @@
// RUN: -mfunction-return=thunk-extern -fsanitize=thread \
// RUN: | FileCheck %s --check-prefix=CHECK-TSAN
+// Check for gcov initialization function pointers.
+// CHECK-GCOV: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
#if !__has_attribute(function_return)
#error "missing attribute support for function_return"
#endif
@@ -104,7 +107,7 @@ void no_attrs(void) {}
// Test synthetic functions.
// CHECK-GCOV: @__llvm_gcov_writeout() unnamed_addr [[EXTERNGCOV:#[0-9]+]]
// CHECK-GCOV: @__llvm_gcov_reset() unnamed_addr [[EXTERNGCOV]]
-// CHECK-GCOV: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]]
+// CHECK-GCOV-NOT: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]]
// CHECK-ASAN: @asan.module_ctor() [[EXTERNASAN:#[0-9]+]]
// CHECK-TSAN: @tsan.module_ctor() [[EXTERNTSAN:#[0-9]+]]
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index d7994bab35d81a..4e3f0aba8c4098 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -49,10 +49,13 @@ int test2(int b) {
/// 0x3430382a '4' '0' '8' '*'
// 408-SAME: i32 875575338
+// Check for gcov initialization function pointers.
+// CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
// 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-NOT: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }
diff --git a/clang/test/CodeGen/coverage-target-attr.c b/clang/test/CodeGen/coverage-target-attr.c
index d46299f5bee223..156e48ba6a31a2 100644
--- a/clang/test/CodeGen/coverage-target-attr.c
+++ b/clang/test/CodeGen/coverage-target-attr.c
@@ -1,9 +1,12 @@
// RUN: %clang_cc1 -emit-llvm -coverage-notes-file=/dev/null -coverage-data-file=/dev/null -triple aarch64-linux-android30 -target-cpu generic -target-feature +tagged-globals -fsanitize=hwaddress %s -o %t
// RUN: FileCheck %s < %t
+// Check for gcov initialization function pointers.
+// CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
// CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr [[ATTR:#[0-9]+]]
// CHECK: define internal void @__llvm_gcov_reset() unnamed_addr [[ATTR]]
-// CHECK: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]]
+// CHECK-NOT: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]]
// CHECK: define internal void @hwasan.module_ctor() [[ATTR2:#[0-9]+]]
// CHECK: attributes [[ATTR]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
// CHECK: attributes [[ATTR2]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
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..f430dd4e36ce37 100644
--- a/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -624,6 +624,23 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr rfn) {
}
}
+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);
+ }
+}
+
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..e6a7cdf3f80a9e 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,7 +122,7 @@ class GCOVProfiler {
Function *createInternalFunction(FunctionType *FTy, StringRef Name,
StringRef MangledType = "");
- void emitGlobalConstructor(
+ void emitModuleInitFunctionPtrs(
SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
bool isFunctionInstrumented(const Function &F);
@@ -914,6 +915,7 @@ bool GCOVProfiler::emitProfileNotes(
GlobalVariable *Counters = new GlobalVariable(
*M, CounterTy, false, GlobalValue::InternalLinkage,
Constant::getNullValue(CounterTy), "__llvm_gcov_ctr");
+ Counters->setSection("__llvm_gcov_ctr_section");
CountersBySP.emplace_back(Counters, SP);
for (size_t I : llvm::seq<size_t>(0, Measured)) {
@@ -980,7 +982,7 @@ bool GCOVProfiler::emitProfileNotes(
}
if (EmitGCDA) {
- emitGlobalConstructor(CountersBySP);
+ emitModuleInitFunctionPtrs(CountersBySP);
EmitGCDA = false;
}
}
@@ -1001,32 +1003,38 @@ Function *GCOVProfiler::createInternalFunction(FunctionType *FTy,
return F;
}
-void GCOVProfiler::emitGlobalConstructor(
+void GCOVProfiler::emitModuleInitFunctionPtrs(
SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {
Function *WriteoutF = insertCounterWriteout(CountersBySP);
Function *ResetF = insertReset(CountersBySP);
- // Create a small bit of code that registers the "__llvm_gcov_writeout" to
- // be executed at exit and the "__llvm_gcov_reset" function to be executed
- // when "__gcov_flush" is called.
- FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
- Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE");
- F->addFnAttr(Attribute::NoInline);
+ // Instead of creating a function call and add it to the constructors list,
+ // create a global variable in the __llvm_covinit section so the functions
+ // can be registered by a constructor in the runtime.
- BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);
- IRBuilder<> Builder(BB);
+ auto &Ctx = M->getContext();
+
+ Type *InitFuncDataTy[] = {
+#define COVINIT_FUNC(Type, LLVMType, Name, Init) LLVMType,
+#include "llvm/ProfileData/InstrProfData.inc"
+ };
- FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
- auto *PFTy = PointerType::get(FTy, 0);
- FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false);
+ auto STy = StructType::get(Ctx, ArrayRef(InitFuncDataTy));
- // Initialize the environment and register the local writeout, flush and
- // reset functions.
- FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);
- Builder.CreateCall(GCOVInit, {WriteoutF, ResetF});
- Builder.CreateRetVoid();
+ Constant *InitFuncPtrs[] = {
+#define COVINIT_FUNC(Type, LLVMType, Name, Init) Init,
+#include "llvm/ProfileData/InstrProfData.inc"
+ };
- appendToGlobalCtors(*M, F, 0);
+ auto *CovInitGV =
+ new GlobalVariable(*M, STy, false, GlobalValue::PrivateLinkage, nullptr,
+ "__llvm_covinit_functions");
+ CovInitGV->setInitializer(ConstantStruct::get(STy, InitFuncPtrs));
+ CovInitGV->setVisibility(GlobalValue::VisibilityTypes::DefaultVisibility);
+ CovInitGV->setSection(getInstrProfSectionName(
+ IPSK_covinit, Triple(M->getTargetTriple()).getObjectFormat()));
+ CovInitGV->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT));
+ CovInitGV->setConstant(true);
}
FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
index 19122b920d1ca4..be53595e9201a0 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
@@ -1,8 +1,11 @@
-;; Ensure __llvm_gcov_(writeout|reset|init) have the correct !kcfi_type
+;; Ensure __llvm_gcov_(writeout|reset) have the correct !kcfi_type
;; with integer normalization.
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; Check for gcov initialization function pointers.
+; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
target triple = "x86_64-unknown-linux-gnu"
define dso_local void @empty() !dbg !5 {
@@ -29,7 +32,5 @@ entry:
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
-; CHECK: define internal void @__llvm_gcov_init()
-; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -440107680}
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi.ll b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
index 1b97d25294cd65..35f863e0fd0752 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
@@ -1,7 +1,10 @@
-;; Ensure __llvm_gcov_(writeout|reset|init) have !kcfi_type with KCFI.
+;; Ensure __llvm_gcov_(writeout|reset) have !kcfi_type with KCFI.
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; Check for gcov initialization function pointers.
+; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
target triple = "x86_64-unknown-linux-gnu"
define dso_local void @empty() !dbg !5 {
@@ -27,7 +30,5 @@ entry:
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
-; CHECK: define internal void @__llvm_gcov_init()
-; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -1522505972}
diff --git a/llvm/test/Transforms/GCOVProfiling/module-flags.ll b/llvm/test/Transforms/GCOVProfiling/module-flags.ll
index 919dd41ea20348..ac8f983055985c 100644
--- a/llvm/test/Transforms/GCOVProfiling/module-flags.ll
+++ b/llvm/test/Transforms/GCOVProfiling/module-flags.ll
@@ -1,6 +1,9 @@
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; Check for gcov initialization function pointers.
+; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
+
target triple = "x86_64-unknown-linux-gnu"
define dso_local void @empty() !dbg !5 {
@@ -30,5 +33,4 @@ entry:
;; Infer uwtable and "frame-pointer" from the module flags.
; CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr #[[#ATTR:]]
; CHECK: define internal void @__llvm_gcov_reset() unnamed_addr #[[#ATTR]]
-; CHECK: define internal void @__llvm_gcov_init() unnamed_addr #[[#ATTR]]
; CHECK: attributes #[[#ATTR]] = { noinline nounwind uwtable "frame-pointer"="all" }
>From 7c6b1d734a23ddbffc67fdafd171ea0f5515891d Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Thu, 12 Sep 2024 17:43:42 -0400
Subject: [PATCH 2/3] Special code for AIX only.
---
clang/test/CodeGen/attr-function-return.c | 7 +---
clang/test/CodeGen/code-coverage.c | 26 ++++++++-----
clang/test/CodeGen/coverage-target-attr.c | 5 +--
compiler-rt/lib/profile/GCDAProfiling.c | 2 +
.../Instrumentation/GCOVProfiling.cpp | 37 ++++++++++++++++++-
.../GCOVProfiling/kcfi-normalize.ll | 17 ++++++---
llvm/test/Transforms/GCOVProfiling/kcfi.ll | 17 ++++++---
.../Transforms/GCOVProfiling/module-flags.ll | 14 ++++---
8 files changed, 88 insertions(+), 37 deletions(-)
diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c
index 9c5cbca5640843..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
@@ -17,9 +17,6 @@
// RUN: -mfunction-return=thunk-extern -fsanitize=thread \
// RUN: | FileCheck %s --check-prefix=CHECK-TSAN
-// Check for gcov initialization function pointers.
-// CHECK-GCOV: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
#if !__has_attribute(function_return)
#error "missing attribute support for function_return"
#endif
@@ -107,7 +104,7 @@ void no_attrs(void) {}
// Test synthetic functions.
// CHECK-GCOV: @__llvm_gcov_writeout() unnamed_addr [[EXTERNGCOV:#[0-9]+]]
// CHECK-GCOV: @__llvm_gcov_reset() unnamed_addr [[EXTERNGCOV]]
-// CHECK-GCOV-NOT: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]]
+// CHECK-GCOV: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]]
// CHECK-ASAN: @asan.module_ctor() [[EXTERNASAN:#[0-9]+]]
// CHECK-TSAN: @tsan.module_ctor() [[EXTERNTSAN:#[0-9]+]]
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index 4e3f0aba8c4098..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:
@@ -49,13 +58,10 @@ int test2(int b) {
/// 0x3430382a '4' '0' '8' '*'
// 408-SAME: i32 875575338
-// Check for gcov initialization function pointers.
-// CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
// Check that the noredzone flag is set on the generated functions.
// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]]
-// CHECK-NOT: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
+// CHECK-ELF: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }
diff --git a/clang/test/CodeGen/coverage-target-attr.c b/clang/test/CodeGen/coverage-target-attr.c
index 156e48ba6a31a2..d46299f5bee223 100644
--- a/clang/test/CodeGen/coverage-target-attr.c
+++ b/clang/test/CodeGen/coverage-target-attr.c
@@ -1,12 +1,9 @@
// RUN: %clang_cc1 -emit-llvm -coverage-notes-file=/dev/null -coverage-data-file=/dev/null -triple aarch64-linux-android30 -target-cpu generic -target-feature +tagged-globals -fsanitize=hwaddress %s -o %t
// RUN: FileCheck %s < %t
-// Check for gcov initialization function pointers.
-// CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
// CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr [[ATTR:#[0-9]+]]
// CHECK: define internal void @__llvm_gcov_reset() unnamed_addr [[ATTR]]
-// CHECK-NOT: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]]
+// CHECK: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]]
// CHECK: define internal void @hwasan.module_ctor() [[ATTR2:#[0-9]+]]
// CHECK: attributes [[ATTR]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
// CHECK: attributes [[ATTR2]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
index f430dd4e36ce37..452a62fcc9d21e 100644
--- a/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -624,6 +624,7 @@ 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 =
@@ -640,6 +641,7 @@ __llvm_profile_gcov_initialize() {
llvm_gcov_init(wfn, rfn);
}
}
+#endif
void __gcov_dump(void) {
for (struct fn_node *f = writeout_fn_list.head; f; f = f->next)
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index e6a7cdf3f80a9e..4a399ad438215a 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -122,6 +122,9 @@ 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);
@@ -982,7 +985,11 @@ bool GCOVProfiler::emitProfileNotes(
}
if (EmitGCDA) {
- emitModuleInitFunctionPtrs(CountersBySP);
+ const llvm::Triple &Triple = llvm::Triple(M->getTargetTriple());
+ if (Triple.getObjectFormat() == llvm::Triple::XCOFF)
+ emitModuleInitFunctionPtrs(CountersBySP);
+ else
+ emitGlobalConstructor(CountersBySP);
EmitGCDA = false;
}
}
@@ -1003,6 +1010,34 @@ Function *GCOVProfiler::createInternalFunction(FunctionType *FTy,
return F;
}
+void GCOVProfiler::emitGlobalConstructor(
+ SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {
+ Function *WriteoutF = insertCounterWriteout(CountersBySP);
+ Function *ResetF = insertReset(CountersBySP);
+
+ // Create a small bit of code that registers the "__llvm_gcov_writeout" to
+ // be executed at exit and the "__llvm_gcov_reset" function to be executed
+ // when "__gcov_flush" is called.
+ FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
+ Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE");
+ F->addFnAttr(Attribute::NoInline);
+
+ BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);
+ IRBuilder<> Builder(BB);
+
+ FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
+ auto *PFTy = PointerType::get(FTy, 0);
+ FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false);
+
+ // Initialize the environment and register the local writeout, flush and
+ // reset functions.
+ FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);
+ Builder.CreateCall(GCOVInit, {WriteoutF, ResetF});
+ Builder.CreateRetVoid();
+
+ appendToGlobalCtors(*M, F, 0);
+}
+
void GCOVProfiler::emitModuleInitFunctionPtrs(
SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {
Function *WriteoutF = insertCounterWriteout(CountersBySP);
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
index be53595e9201a0..fa19fcfe271e07 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
@@ -1,12 +1,15 @@
-;; Ensure __llvm_gcov_(writeout|reset) have the correct !kcfi_type
+;; Ensure __llvm_gcov_(writeout|reset|init) have the correct !kcfi_type
;; with integer normalization.
; RUN: mkdir -p %t && cd %t
-; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
-; Check for gcov initialization function pointers.
-; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
-target triple = "x86_64-unknown-linux-gnu"
+; Check for gcov initialization function pointers for XCOFF.
+; CHECK-XCOFF: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
define dso_local void @empty() !dbg !5 {
entry:
@@ -32,5 +35,7 @@ entry:
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
+; CHECK-ELF: define internal void @__llvm_gcov_init()
+; CHECK-ELF-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -440107680}
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi.ll b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
index 35f863e0fd0752..bfa3a6403578f2 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
@@ -1,11 +1,14 @@
-;; Ensure __llvm_gcov_(writeout|reset) have !kcfi_type with KCFI.
+;; Ensure __llvm_gcov_(writeout|reset|init) have !kcfi_type with KCFI.
; RUN: mkdir -p %t && cd %t
-; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
-; Check for gcov initialization function pointers.
-; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
-target triple = "x86_64-unknown-linux-gnu"
+; Check for gcov initialization function pointers for XCOFF.
+; CHECK-XCOFF: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
define dso_local void @empty() !dbg !5 {
entry:
@@ -30,5 +33,7 @@ entry:
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
+; CHECK-ELF: define internal void @__llvm_gcov_init()
+; CHECK-ELF-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -1522505972}
diff --git a/llvm/test/Transforms/GCOVProfiling/module-flags.ll b/llvm/test/Transforms/GCOVProfiling/module-flags.ll
index ac8f983055985c..77fc77bfe18cc3 100644
--- a/llvm/test/Transforms/GCOVProfiling/module-flags.ll
+++ b/llvm/test/Transforms/GCOVProfiling/module-flags.ll
@@ -1,10 +1,13 @@
; RUN: mkdir -p %t && cd %t
-; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: opt < %s -S -passes=insert-gcov-profiling \
+; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
+; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
-; Check for gcov initialization function pointers.
-; CHECK: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
-
-target triple = "x86_64-unknown-linux-gnu"
+; Check for gcov initialization function pointers for XCOFF.
+; CHECK-XCOFF: @__llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit"
define dso_local void @empty() !dbg !5 {
entry:
@@ -33,4 +36,5 @@ entry:
;; Infer uwtable and "frame-pointer" from the module flags.
; CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr #[[#ATTR:]]
; CHECK: define internal void @__llvm_gcov_reset() unnamed_addr #[[#ATTR]]
+; CHECK-ELF: define internal void @__llvm_gcov_init() unnamed_addr #[[#ATTR]]
; CHECK: attributes #[[#ATTR]] = { noinline nounwind uwtable "frame-pointer"="all" }
>From 258103e9a6813e353f203d4ca10db059a0d0902d Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Mon, 16 Sep 2024 09:27:07 -0400
Subject: [PATCH 3/3] Fix lit test.
---
clang/test/CodeGen/code-coverage.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index 30c59d58380def..b65a1fe118b738 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -29,9 +29,6 @@
// 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:
@@ -58,6 +55,9 @@ int test2(int b) {
/// 0x3430382a '4' '0' '8' '*'
// 408-SAME: i32 875575338
+// 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"
+
// Check that the noredzone flag is set on the generated functions.
// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]]
More information about the cfe-commits
mailing list