Skip to content

[PGO] Initialize GCOV Writeout and Reset Functions in the Runtime on AIX #108570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions clang/test/CodeGen/code-coverage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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-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-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-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-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-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-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

Expand Down Expand Up @@ -49,10 +55,13 @@ int test2(int b) {
/// 0x3430382a '4' '0' '8' '*'
// 408-SAME: i32 875575338

// Check for gcov initialization function pointers.
// 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: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
// CHECK-CTOR-INIT: void @__llvm_gcov_init() unnamed_addr [[NRZ]]

// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }

Expand Down
23 changes: 23 additions & 0 deletions compiler-rt/include/profile/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand All @@ -781,6 +798,10 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"

// FIXME: Placeholder for Windows. Windows currently does not initialize
// the GCOV functions in the runtime.
#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
Expand All @@ -800,6 +821,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)
Expand All @@ -821,6 +843,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
Expand Down
19 changes: 19 additions & 0 deletions compiler-rt/lib/profile/GCDAProfiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,25 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr rfn) {
}
}

#if defined(_AIX)
COMPILER_RT_VISIBILITY __attribute__((constructor)) void
__llvm_profile_gcov_initialize() {
const __llvm_gcov_init_func_struct *InitFuncStart =
__llvm_profile_begin_covinit();
const __llvm_gcov_init_func_struct *InitFuncEnd =
__llvm_profile_end_covinit();

for (const __llvm_gcov_init_func_struct *Ptr = InitFuncStart;
Ptr != InitFuncEnd; ++Ptr) {
fn_ptr wfn = (fn_ptr)Ptr->WriteoutFunction;
fn_ptr rfn = (fn_ptr)Ptr->ResetFunction;
if (!(wfn && rfn))
continue;
llvm_gcov_init(wfn, rfn);
}
}
#endif

void __gcov_dump(void) {
for (struct fn_node *f = writeout_fn_list.head; f; f = f->next)
f->fn();
Expand Down
11 changes: 11 additions & 0 deletions compiler-rt/lib/profile/InstrProfiling.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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_ */
5 changes: 4 additions & 1 deletion compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
52 changes: 52 additions & 0 deletions compiler-rt/test/profile/AIX/gcov-undef-sym.test
Original file line number Diff line number Diff line change
@@ -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: %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: %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: %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();
}
23 changes: 23 additions & 0 deletions llvm/include/llvm/ProfileData/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand All @@ -781,6 +798,10 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"

// FIXME: Placeholder for Windows. Windows currently does not initialize
// the GCOV functions in the runtime.
#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
Expand All @@ -800,6 +821,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)
Expand All @@ -821,6 +843,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
Expand Down
28 changes: 28 additions & 0 deletions llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2962,13 +2964,39 @@ 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);
const XCOFF::StorageMappingClass MappingClass =
TM.Options.XCOFFReadOnlyPointers ? XCOFF::XMC_RO : XCOFF::XMC_RW;
if (OutContext.hasXCOFFSection(
"__llvm_covinit",
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);
}
}

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.
if (M.empty() && TOCDataGlobalVars.empty())
return;

emitPGORefs(M);
emitGCOVRefs();

// Switch to section to emit TOC base.
OutStreamer->switchSection(getObjFileLowering().getTOCBaseSection());
Expand Down
Loading
Loading