[clang] [compiler-rt] [llvm] [PGO] Initialize GCOV Writeout and Reset Functions in the Runtime on AIX (PR #108570)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 15 08:16:09 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/7] 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/7] 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/7] 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]+]]
>From b1eaf18d91252feb3826afc53bc8975c86848bde Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Wed, 18 Sep 2024 10:37:46 -0400
Subject: [PATCH 4/7] Improve new test.
---
compiler-rt/test/profile/AIX/gcov-undef-sym.test | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/compiler-rt/test/profile/AIX/gcov-undef-sym.test b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
index e377b321ca66cd..db9053952d95b7 100644
--- a/compiler-rt/test/profile/AIX/gcov-undef-sym.test
+++ b/compiler-rt/test/profile/AIX/gcov-undef-sym.test
@@ -6,7 +6,7 @@ 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: %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
@@ -15,7 +15,7 @@ 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: %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
@@ -24,7 +24,7 @@ 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: %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
>From 11793f38a9a7b6d05cd2cfdf5c1a09f3bf3cc5c3 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Fri, 4 Oct 2024 17:55:23 -0400
Subject: [PATCH 5/7] Address review comments.
---
clang/test/CodeGen/attr-function-return.c | 2 +-
clang/test/CodeGen/code-coverage.c | 16 +--
compiler-rt/include/profile/InstrProfData.inc | 3 +-
.../llvm/ProfileData/InstrProfData.inc | 3 +-
.../Instrumentation/GCOVProfiling.cpp | 4 +-
.../test/CodeGen/PowerPC/gcov_ctr_ref_init.ll | 126 ++++++++++++++++++
.../GCOVProfiling/kcfi-normalize.ll | 13 +-
llvm/test/Transforms/GCOVProfiling/kcfi.ll | 13 +-
.../Transforms/GCOVProfiling/module-flags.ll | 11 +-
9 files changed, 162 insertions(+), 29 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c
index 1aca3b1bfa5b59..df2cabf28693a3 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-prefixes=CHECK-GCOV
+// RUN: | FileCheck %s --check-prefix=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 b65a1fe118b738..4e3364df217854 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -4,17 +4,17 @@
/// 4.8 (default, compatible with gcov 7) emits the exit block the second.
// RUN: rm -rf %t && mkdir %t && cd %t
// 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: FileCheck --check-prefixes=CHECK,CHECK-CTOR-INIT,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: FileCheck --check-prefixes=CHECK,CHECK-CTOR-INIT,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: FileCheck --check-prefixes=CHECK,CHECK-CTOR-INIT,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: FileCheck --check-prefixes=CHECK,CHECK-RT-INIT,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: FileCheck --check-prefixes=CHECK,CHECK-RT-INIT,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: FileCheck --check-prefixes=CHECK,CHECK-RT-INIT,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
@@ -56,12 +56,12 @@ int test2(int b) {
// 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-RT-INIT: @__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-ELF: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
+// CHECK-CTOR-INIT: 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 591fc1401e1aab..c66b0465a0b548 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -798,7 +798,8 @@ 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.
+// FIXME: Placeholder for Windows. Windows currently does not initialize
+// the GCOV functions in the runtime.
#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
#ifdef _WIN32
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index 591fc1401e1aab..c66b0465a0b548 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -798,7 +798,8 @@ 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.
+// FIXME: Placeholder for Windows. Windows currently does not initialize
+// the GCOV functions in the runtime.
#define INSTR_PROF_COVINIT_COFF ".lcovd$M"
#ifdef _WIN32
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 4a399ad438215a..3cc9484dfe73cd 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -918,7 +918,9 @@ bool GCOVProfiler::emitProfileNotes(
GlobalVariable *Counters = new GlobalVariable(
*M, CounterTy, false, GlobalValue::InternalLinkage,
Constant::getNullValue(CounterTy), "__llvm_gcov_ctr");
- Counters->setSection("__llvm_gcov_ctr_section");
+ const llvm::Triple &Triple = llvm::Triple(M->getTargetTriple());
+ if (Triple.getObjectFormat() == llvm::Triple::XCOFF)
+ Counters->setSection("__llvm_gcov_ctr_section");
CountersBySP.emplace_back(Counters, SP);
for (size_t I : llvm::seq<size_t>(0, Measured)) {
diff --git a/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
new file mode 100644
index 00000000000000..91f55fd71aa19a
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
@@ -0,0 +1,126 @@
+; Tests if the __llvm_gcov_ctr section contains a .ref pseudo-op
+; referring to the __llvm_covinit section.
+; RUN: llc < %s | FileCheck %s
+
+target datalayout = "E-m:a-p:32:32-Fi32-i64:64-n32"
+target triple = "powerpc-ibm-aix"
+
+; CHECK: .csect __llvm_covinit[RW],3
+; CHECK: .vbyte 4, __llvm_gcov_writeout[DS]
+; CHECK-NEXT: .vbyte 4, __llvm_gcov_reset[DS]
+; 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-NEXT: .ref __llvm_covinit[RW]
+
+%emit_function_args_ty = type { i32, i32, i32 }
+%emit_arcs_args_ty = type { i32, ptr }
+%file_info = type { %start_file_args_ty, i32, ptr, ptr }
+%start_file_args_ty = type { ptr, i32, i32 }
+
+ at __llvm_gcov_ctr = internal global [1 x i64] zeroinitializer, section "__llvm_gcov_ctr_section"
+ at __llvm_gcov_ctr.1 = internal global [1 x i64] zeroinitializer, section "__llvm_gcov_ctr_section"
+ at 0 = private unnamed_addr constant [10 x i8] c"test.gcda\00", align 1
+ at __llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant [2 x %emit_function_args_ty] [%emit_function_args_ty { i32 0, i32 1961870044, i32 -801444649 }, %emit_function_args_ty { i32 1, i32 1795396728, i32 -801444649 }]
+ at __llvm_internal_gcov_emit_arcs_args.0 = internal unnamed_addr constant [2 x %emit_arcs_args_ty] [%emit_arcs_args_ty { i32 1, ptr @__llvm_gcov_ctr }, %emit_arcs_args_ty { i32 1, ptr @__llvm_gcov_ctr.1 }]
+ at __llvm_internal_gcov_emit_file_info = internal unnamed_addr constant [1 x %file_info] [%file_info { %start_file_args_ty { ptr @0, i32 875575338, i32 -801444649 }, i32 2, ptr @__llvm_internal_gcov_emit_function_args.0, ptr @__llvm_internal_gcov_emit_arcs_args.0 }]
+ at __llvm_covinit_functions = private constant { ptr, ptr } { ptr @__llvm_gcov_writeout, ptr @__llvm_gcov_reset }, section "__llvm_covinit", align 8
+
+define i32 @bar() {
+entry:
+ %gcov_ctr = load i64, ptr @__llvm_gcov_ctr, align 8
+ %0 = add i64 %gcov_ctr, 1
+ store i64 %0, ptr @__llvm_gcov_ctr, align 8
+ ret i32 1
+}
+
+define i32 @main() {
+entry:
+ %gcov_ctr = load i64, ptr @__llvm_gcov_ctr.1, align 8
+ %0 = add i64 %gcov_ctr, 1
+ store i64 %0, ptr @__llvm_gcov_ctr.1, align 8
+ %retval = alloca i32, align 4
+ store i32 0, ptr %retval, align 4
+ %call = call i32 @bar()
+ %sub = sub nsw i32 %call, 1
+ ret i32 %sub
+}
+
+define internal void @__llvm_gcov_writeout() unnamed_addr {
+entry:
+ br label %file.loop.header
+
+file.loop.header: ; preds = %file.loop.latch, %entry
+ %file_idx = phi i32 [ 0, %entry ], [ %next_file_idx, %file.loop.latch ]
+ %0 = getelementptr inbounds [1 x %file_info], ptr @__llvm_internal_gcov_emit_file_info, i32 0, i32 %file_idx
+ %start_file_args = getelementptr inbounds nuw %file_info, ptr %0, i32 0, i32 0
+ %1 = getelementptr inbounds nuw %start_file_args_ty, ptr %start_file_args, i32 0, i32 0
+ %filename = load ptr, ptr %1, align 4
+ %2 = getelementptr inbounds nuw %start_file_args_ty, ptr %start_file_args, i32 0, i32 1
+ %version = load i32, ptr %2, align 4
+ %3 = getelementptr inbounds nuw %start_file_args_ty, ptr %start_file_args, i32 0, i32 2
+ %stamp = load i32, ptr %3, align 4
+ call void @llvm_gcda_start_file(ptr %filename, i32 %version, i32 %stamp)
+ %4 = getelementptr inbounds nuw %file_info, ptr %0, i32 0, i32 1
+ %num_ctrs = load i32, ptr %4, align 4
+ %5 = getelementptr inbounds nuw %file_info, ptr %0, i32 0, i32 2
+ %emit_function_args = load ptr, ptr %5, align 4
+ %6 = getelementptr inbounds nuw %file_info, ptr %0, i32 0, i32 3
+ %emit_arcs_args = load ptr, ptr %6, align 4
+ %7 = icmp slt i32 0, %num_ctrs
+ br i1 %7, label %counter.loop.header, label %file.loop.latch
+
+counter.loop.header: ; preds = %counter.loop.header, %file.loop.header
+ %ctr_idx = phi i32 [ 0, %file.loop.header ], [ %15, %counter.loop.header ]
+ %8 = getelementptr inbounds %emit_function_args_ty, ptr %emit_function_args, i32 %ctr_idx
+ %9 = getelementptr inbounds nuw %emit_function_args_ty, ptr %8, i32 0, i32 0
+ %ident = load i32, ptr %9, align 4
+ %10 = getelementptr inbounds nuw %emit_function_args_ty, ptr %8, i32 0, i32 1
+ %func_checkssum = load i32, ptr %10, align 4
+ %11 = getelementptr inbounds nuw %emit_function_args_ty, ptr %8, i32 0, i32 2
+ %cfg_checksum = load i32, ptr %11, align 4
+ call void @llvm_gcda_emit_function(i32 %ident, i32 %func_checkssum, i32 %cfg_checksum)
+ %12 = getelementptr inbounds %emit_arcs_args_ty, ptr %emit_arcs_args, i32 %ctr_idx
+ %13 = getelementptr inbounds nuw %emit_arcs_args_ty, ptr %12, i32 0, i32 0
+ %num_counters = load i32, ptr %13, align 4
+ %14 = getelementptr inbounds nuw %emit_arcs_args_ty, ptr %12, i32 0, i32 1
+ %counters = load ptr, ptr %14, align 4
+ call void @llvm_gcda_emit_arcs(i32 %num_counters, ptr %counters)
+ %15 = add i32 %ctr_idx, 1
+ %16 = icmp slt i32 %15, %num_ctrs
+ br i1 %16, label %counter.loop.header, label %file.loop.latch
+
+file.loop.latch: ; preds = %counter.loop.header, %file.loop.header
+ call void @llvm_gcda_summary_info()
+ call void @llvm_gcda_end_file()
+ %next_file_idx = add i32 %file_idx, 1
+ %17 = icmp slt i32 %next_file_idx, 1
+ br i1 %17, label %file.loop.header, label %exit
+
+exit: ; preds = %file.loop.latch
+ ret void
+}
+
+declare void @llvm_gcda_start_file(ptr, i32, i32)
+
+declare void @llvm_gcda_emit_function(i32, i32, i32)
+
+declare void @llvm_gcda_emit_arcs(i32, ptr)
+
+declare void @llvm_gcda_summary_info()
+
+declare void @llvm_gcda_end_file()
+
+define internal void @__llvm_gcov_reset() unnamed_addr {
+entry:
+ call void @llvm.memset.p0.i64(ptr @__llvm_gcov_ctr, i8 0, i64 8, i1 false)
+ call void @llvm.memset.p0.i64(ptr @__llvm_gcov_ctr.1, i8 0, i64 8, i1 false)
+ ret void
+}
+
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+
+
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
index fa19fcfe271e07..9ad0418025e56c 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
@@ -3,13 +3,14 @@
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: --check-prefixes=CHECK,CHECK-CTOR-INIT %s
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
+; RUN: --check-prefixes=CHECK,CHECK-RT-INIT %s
-; 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"
+; Check for gcov initialization function pointers when we initialize
+; the writeout and reset functions in the runtime.
+; CHECK-RT-INIT: @__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:
@@ -35,7 +36,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-CTOR-INIT: define internal void @__llvm_gcov_init()
+; CHECK-CTOR-INIT-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 bfa3a6403578f2..5e0e91fc92f5f7 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
@@ -2,13 +2,14 @@
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: --check-prefixes=CHECK,CHECK-CTOR-INIT %s
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
+; RUN: --check-prefixes=CHECK,CHECK-RT-INIT %s
-; 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"
+; Check for gcov initialization function pointers when we initialize
+; the writeout and reset functions in the runtime.
+; CHECK-RT-INIT: @__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,7 +34,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-CTOR-INIT: define internal void @__llvm_gcov_init()
+; CHECK-CTOR-INIT-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 77fc77bfe18cc3..59f116d0d7e655 100644
--- a/llvm/test/Transforms/GCOVProfiling/module-flags.ll
+++ b/llvm/test/Transforms/GCOVProfiling/module-flags.ll
@@ -1,13 +1,14 @@
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=x86_64-unknown-linux-gnu | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-ELF %s
+; RUN: --check-prefixes=CHECK,CHECK-CTOR-INIT %s
; RUN: opt < %s -S -passes=insert-gcov-profiling \
; RUN: -mtriple=powerpc64-ibm-aix | FileCheck \
-; RUN: --check-prefixes=CHECK,CHECK-XCOFF %s
+; RUN: --check-prefixes=CHECK,CHECK-RT-INIT %s
-; 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"
+; Check for gcov initialization function pointers when we initialize
+; the writeout and reset functions in the runtime.
+; CHECK-RT-INIT: @__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:
@@ -36,5 +37,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-CTOR-INIT: define internal void @__llvm_gcov_init() unnamed_addr #[[#ATTR]]
; CHECK: attributes #[[#ATTR]] = { noinline nounwind uwtable "frame-pointer"="all" }
>From b7c470ad6ce64bbd4cd7d513be98a57f7d1740f1 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Fri, 4 Oct 2024 19:20:02 -0400
Subject: [PATCH 6/7] Fix the code that inserts the .ref pseudo-op when
xcoff-roptr is in effect.
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 9 +++++++--
llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll | 9 ++++++---
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 3251340aa67a6a..e32ba66dd13d05 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2976,10 +2976,15 @@ void PPCAIXAsmPrinter::emitGCOVRefs() {
/*MultiSymbolsAllowed*/ true);
OutStreamer->switchSection(CtrSection);
+ const XCOFF::StorageMappingClass MappingClass =
+ TM.Options.XCOFFReadOnlyPointers ? XCOFF::XMC_RO : XCOFF::XMC_RW;
if (OutContext.hasXCOFFSection(
"__llvm_covinit",
- XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) {
- MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_covinit[RW]");
+ XCOFF::CsectProperties(MappingClass, XCOFF::XTY_SD))) {
+ const char *SymbolStr = TM.Options.XCOFFReadOnlyPointers
+ ? "__llvm_covinit[RO]"
+ : "__llvm_covinit[RW]";
+ MCSymbol *S = OutContext.getOrCreateSymbol(SymbolStr);
OutStreamer->emitXCOFFRefDirective(S);
}
}
diff --git a/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
index 91f55fd71aa19a..990fed30a059e4 100644
--- a/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
+++ b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
@@ -1,11 +1,13 @@
; Tests if the __llvm_gcov_ctr section contains a .ref pseudo-op
; referring to the __llvm_covinit section.
-; RUN: llc < %s | FileCheck %s
+; RUN: llc < %s | FileCheck --check-prefixes=CHECK,CHECK-RW %s
+; RUN: llc -mxcoff-roptr < %s | FileCheck --check-prefixes=CHECK,CHECK-RO %s
target datalayout = "E-m:a-p:32:32-Fi32-i64:64-n32"
target triple = "powerpc-ibm-aix"
-; CHECK: .csect __llvm_covinit[RW],3
+; CHECK-RW: .csect __llvm_covinit[RW],3
+; CHECK-RO: .csect __llvm_covinit[RO],3
; CHECK: .vbyte 4, __llvm_gcov_writeout[DS]
; CHECK-NEXT: .vbyte 4, __llvm_gcov_reset[DS]
; CHECK: __llvm_gcov_ctr.1:
@@ -14,7 +16,8 @@ target triple = "powerpc-ibm-aix"
; 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-NEXT: .ref __llvm_covinit[RW]
+; CHECK-RW-NEXT: .ref __llvm_covinit[RW]
+; CHECK-RO-NEXT: .ref __llvm_covinit[RO]
%emit_function_args_ty = type { i32, i32, i32 }
%emit_arcs_args_ty = type { i32, ptr }
>From 9c8505ce3c05e1dda8e7677f6ca36db96f932261 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qwu at ibm.com>
Date: Tue, 15 Oct 2024 12:24:29 -0400
Subject: [PATCH 7/7] Address code review.
---
.../test/CodeGen/PowerPC/gcov_ctr_ref_init.ll | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
index 990fed30a059e4..197d2c98e81134 100644
--- a/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
+++ b/llvm/test/CodeGen/PowerPC/gcov_ctr_ref_init.ll
@@ -8,14 +8,19 @@ target triple = "powerpc-ibm-aix"
; CHECK-RW: .csect __llvm_covinit[RW],3
; CHECK-RO: .csect __llvm_covinit[RO],3
-; CHECK: .vbyte 4, __llvm_gcov_writeout[DS]
-; CHECK-NEXT: .vbyte 4, __llvm_gcov_reset[DS]
-; CHECK: __llvm_gcov_ctr.1:
+; CHECK-NEXT: .align 3 # @__llvm_covinit_functions
+; CHECK-NEXT: L..__llvm_covinit_functions:
+; CHECK-NEXT: .vbyte 4, __llvm_gcov_writeout[DS]
+; CHECK-NEXT: .vbyte 4, __llvm_gcov_reset[DS]
+; CHECK: L.._MergedGlobals:
+; CHECK-NEXT: __llvm_gcov_ctr:
+; CHECK-NEXT: .space 16
+; CHECK-NEXT: __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-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]
More information about the cfe-commits
mailing list