-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[AIX] PGO codegen changes for function-sections. #139761
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
b39751c
f8da9c2
d2cac52
e2ba1aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// RUN: split-file %s %t | ||
// RUN: cd %t | ||
// RUN: %clang_pgogen -ffunction-sections main.c -c -o main.o | ||
// RUN: %clang_pgogen -ffunction-sections needs_gc.c -c -o needs_gc.o | ||
// RUN: %clang_pgogen main.o needs_gc.o -o needs_gc.out | ||
// RUN: env LLVM_PROFILE_FILE=needs_gc.profraw %run ./needs_gc.out > /dev/null | ||
// RUN: llvm-profdata show --all-functions needs_gc.profraw | FileCheck %s | ||
|
||
// CHECK-DAG: main | ||
// CHECK-DAG: baz | ||
// CHECK-DAG: get_message | ||
|
||
|
||
//--- main.c | ||
const char* get_message(void) { | ||
return "Hello World!"; | ||
} | ||
|
||
const char* baz(); | ||
|
||
int printf(const char*, ...); | ||
|
||
int main(void) { | ||
printf("%s\n", baz()); | ||
} | ||
|
||
//--- needs_gc.c | ||
extern int not_def_one(const char *); | ||
extern double not_def_two(void); | ||
|
||
extern const char* get_message(void); | ||
|
||
char buf[512]; | ||
int foo(const char *ptr, unsigned long size) { | ||
void *memcpy(void *, const void *, unsigned long); | ||
memcpy(buf, ptr, size); | ||
return not_def_one(buf); | ||
} | ||
|
||
double bar(void) { | ||
return not_def_two(); | ||
} | ||
|
||
|
||
const char* baz() { | ||
return get_message(); | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -253,6 +253,22 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter { | |||||
DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>> | ||||||
GOAliasMap; | ||||||
|
||||||
// The __profd_* symbol for the profiling instrumentation data and the | ||||||
// corresponding __profc_* counters it refernces. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
struct ProfilingSubSection { | ||||||
MCSectionXCOFF *ProfD; | ||||||
MCSectionXCOFF *ProfC; | ||||||
}; | ||||||
|
||||||
// Collect the 'sub-sections' of the profile-generate symbols | ||||||
// so we can: | ||||||
// 1) rename to the common CSECT name after emission. | ||||||
// 2) emit the refs from the profc_ symbol to the related CSECTs. | ||||||
SmallVector<ProfilingSubSection> ProfGenSubSections; | ||||||
|
||||||
void emitSharedSectionPGORefs(Module &M); | ||||||
void emitSplitSectionPGORefs(); | ||||||
|
||||||
uint16_t getNumberOfVRSaved(); | ||||||
void emitTracebackTable(); | ||||||
|
||||||
|
@@ -2810,6 +2826,57 @@ void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) { | |||||
MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( | ||||||
getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); | ||||||
|
||||||
// When compiling with function sections enabled, we need some special | ||||||
// codegen to rename the CSECTs. For each profiling data symbol find its | ||||||
// associated profiling counters. | ||||||
if (TM.getFunctionSections() && | ||||||
Csect->getName().starts_with("__llvm_prf_data.")) { | ||||||
// Unraveling the initializer to find the related counters variable. The | ||||||
// initializer is a structure whose third member is a subtract expression | ||||||
// between the counters label and the label for the start of this structure. | ||||||
// Use the subtract expression to get the GlobalValue for the counters | ||||||
// global. | ||||||
assert(GV->hasInitializer() && | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this logic is tied to the logic that generates the initializer. Can we extract it into a query function in InstrProf.h? Or if we can somehow use the profd's layout described through the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really dislike this part because we are so tightly coupled to the implementation that if anyone changed the initializer format they would have to simultaneously modify the PPC target which is a problem. For ELF the section keys on the Comdats carry the relationship info in the IR implicitly. What do you think of an alternative approach where we could use a metadata node to explicitly attach to dependancy info to the data symbol? https://llvm.org/docs/LangRef.html#associated-metadata is a similar idea for ELF. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, this is really brittle and may force developers changing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
that will have to happen early in the pipeline, when the profd's initializer is created. Then that metadata will have to be maintained by passes until object/asm generation. No strong objection to it, but I slightly prefer to just refactor this into a utility function in InstrProf.h:
|
||||||
"profiling data symbol must have an initializer"); | ||||||
assert(isa<ConstantStruct>(GV->getInitializer()) && | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can probably pull out the |
||||||
"expect the initializer for a profiling data symbol to be a struct"); | ||||||
const ConstantStruct *Initializer = | ||||||
cast<ConstantStruct>(GV->getInitializer()); | ||||||
|
||||||
// The initializer structure is: { i64, i64, i32, ptr, ptr, i32, [4 x i16] } | ||||||
// and the reference to the global variable for the counters is in the | ||||||
// first i32 member. | ||||||
const Constant *Member = Initializer->getAggregateElement(2); | ||||||
assert(Member && "profiling data symbol has more then 3 elements"); | ||||||
|
||||||
// Want to decompose a constant expression of the form: | ||||||
// sub (ptrtoint (ptr @__profc_sym), ptrtoint (ptr @__profd_sym)) | ||||||
// to get the GlobalVariable for the '@__profc_sym` symbol. | ||||||
assert(isa<ConstantExpr>(Member) && | ||||||
"expected member initializer is a constant expression."); | ||||||
const ConstantExpr *CExpr = cast<ConstantExpr>(Member); | ||||||
assert(CExpr->getOpcode() == Instruction::Sub && | ||||||
"expected member intializer is a sub expression."); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Value *V1 = CExpr->getOperand(0); | ||||||
assert(V1 && isa<ConstantExpr>(V1) && | ||||||
"expected sub expression operand to be constant expr."); | ||||||
ConstantExpr *PointerToIntExpr = cast<ConstantExpr>(V1); | ||||||
assert(PointerToIntExpr->isCast() && "unexpected operand type."); | ||||||
|
||||||
Value *PointerToIntOperand = PointerToIntExpr->getOperand(0); | ||||||
assert(isa<GlobalVariable>(PointerToIntOperand) && | ||||||
"expected global variable of profc symbol"); | ||||||
|
||||||
const GlobalVariable *ProfCGV = cast<GlobalVariable>(PointerToIntOperand); | ||||||
// Map the global variable to its CSECT. | ||||||
SectionKind ProfCKind = getObjFileLowering().getKindForGlobal(GV, TM); | ||||||
MCSectionXCOFF *ProfCCsect = cast<MCSectionXCOFF>( | ||||||
getObjFileLowering().SectionForGlobal(ProfCGV, ProfCKind, TM)); | ||||||
|
||||||
ProfGenSubSections.push_back({Csect, ProfCCsect}); | ||||||
} | ||||||
|
||||||
// Switch to the containing csect. | ||||||
OutStreamer->switchSection(Csect); | ||||||
|
||||||
|
@@ -2911,7 +2978,7 @@ void PPCAIXAsmPrinter::emitFunctionEntryLabel() { | |||||
getObjFileLowering().getFunctionEntryPointSymbol(Alias, TM)); | ||||||
} | ||||||
|
||||||
void PPCAIXAsmPrinter::emitPGORefs(Module &M) { | ||||||
void PPCAIXAsmPrinter::emitSharedSectionPGORefs(Module &M) { | ||||||
if (!OutContext.hasXCOFFSection( | ||||||
"__llvm_prf_cnts", | ||||||
XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) | ||||||
|
@@ -2960,6 +3027,54 @@ void PPCAIXAsmPrinter::emitPGORefs(Module &M) { | |||||
} | ||||||
} | ||||||
|
||||||
void PPCAIXAsmPrinter::emitSplitSectionPGORefs() { | ||||||
MCSymbol *NamesSym = nullptr; | ||||||
MCSymbol *VNDSSym = nullptr; | ||||||
|
||||||
if (OutContext.hasXCOFFSection( | ||||||
"__llvm_prf_names", | ||||||
XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) | ||||||
NamesSym = OutContext.getOrCreateSymbol("__llvm_prf_names[RO]"); | ||||||
|
||||||
if (OutContext.hasXCOFFSection( | ||||||
"__llvm_prf_vnds", | ||||||
XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) | ||||||
VNDSSym = OutContext.getOrCreateSymbol("__llvm_prf_vnds[RW]"); | ||||||
|
||||||
for (auto SubSections : ProfGenSubSections) { | ||||||
MCSectionXCOFF *ProfDCsect = SubSections.ProfD; | ||||||
MCSectionXCOFF *ProfCCsect = SubSections.ProfC; | ||||||
|
||||||
OutStreamer->switchSection(ProfCCsect); | ||||||
|
||||||
if (NamesSym) | ||||||
OutStreamer->emitXCOFFRefDirective(NamesSym); | ||||||
|
||||||
if (VNDSSym) | ||||||
OutStreamer->emitXCOFFRefDirective(VNDSSym); | ||||||
|
||||||
OutStreamer->emitXCOFFRefDirective(ProfDCsect->getQualNameSymbol()); | ||||||
|
||||||
// Rename the subsection for the counters | ||||||
OutStreamer->emitXCOFFRenameDirective(ProfCCsect->getQualNameSymbol(), | ||||||
"__llvm_prf_cnts"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use |
||||||
OutStreamer->addBlankLine(); | ||||||
|
||||||
// Rename the subsection for the data. | ||||||
OutStreamer->switchSection(ProfDCsect); | ||||||
OutStreamer->emitXCOFFRenameDirective(ProfDCsect->getQualNameSymbol(), | ||||||
"__llvm_prf_data"); | ||||||
OutStreamer->addBlankLine(); | ||||||
} | ||||||
} | ||||||
|
||||||
void PPCAIXAsmPrinter::emitPGORefs(Module &M) { | ||||||
if (!TM.getFunctionSections()) | ||||||
emitSharedSectionPGORefs(M); | ||||||
else | ||||||
emitSplitSectionPGORefs(); | ||||||
} | ||||||
|
||||||
void PPCAIXAsmPrinter::emitGCOVRefs() { | ||||||
if (!OutContext.hasXCOFFSection( | ||||||
"__llvm_gcov_ctr_section", | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
; RUN: llc --function-sections -mtriple powerpc-ibm-aix-xcoff < %s | \ | ||
; RUN: FileCheck %s | ||
|
||
; RUN: llc --function-sections -mtriple powerpc64-ibm-aix-xcoff < %s | \ | ||
; RUN: FileCheck %s | ||
|
||
@i = external local_unnamed_addr global i32, align 4 | ||
@__llvm_profile_raw_version = weak hidden local_unnamed_addr constant i64 72057594037927944 | ||
@__profc_func1 = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 | ||
@__profd_func1 = private global { i64, i64, i32, ptr, ptr, i32, [4 x i16] } { i64 -2545542355363006406, i64 742261418966908927, i32 sub (i32 ptrtoint (ptr @__profc_func1 to i32), i32 ptrtoint (ptr @__profd_func1 to i32)), ptr @func1.local, ptr null, i32 1, [4 x i16] zeroinitializer }, section "__llvm_prf_data", align 8 | ||
@__profc_func2 = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 | ||
@__profd_func2 = private global { i64, i64, i32, ptr, ptr, i32, [4 x i16] } { i64 -4377547752858689819, i64 742261418966908927, i32 sub (i32 ptrtoint (ptr @__profc_func2 to i32), i32 ptrtoint (ptr @__profd_func2 to i32)), ptr @func2.local, ptr null, i32 1, [4 x i16] zeroinitializer }, section "__llvm_prf_data", align 8 | ||
@__llvm_prf_nm = private constant [13 x i8] c"\0B\00func1\01func2", section "__llvm_prf_names", align 1 | ||
@__llvm_profile_filename = weak hidden local_unnamed_addr constant [19 x i8] c"default_%m.profraw\00" | ||
@llvm.used = appending global [3 x ptr] [ptr @__llvm_prf_nm, ptr @__profd_func1, ptr @__profd_func2], section "llvm.metadata" | ||
|
||
@func1.local = private alias i32 (), ptr @func1 | ||
@func2.local = private alias i32 (), ptr @func2 | ||
|
||
define i32 @func1() { | ||
entry: | ||
%pgocount = load i64, ptr @__profc_func1, align 8 | ||
%0 = add i64 %pgocount, 1 | ||
store i64 %0, ptr @__profc_func1, align 8 | ||
%1 = load i32, ptr @i, align 4 | ||
ret i32 %1 | ||
} | ||
|
||
define i32 @func2() { | ||
entry: | ||
%pgocount = load i64, ptr @__profc_func2, align 8 | ||
%0 = add i64 %pgocount, 1 | ||
store i64 %0, ptr @__profc_func2, align 8 | ||
%1 = load i32, ptr @i, align 4 | ||
%call = tail call i32 @external_func(i32 noundef %1) | ||
ret i32 %call | ||
} | ||
|
||
declare i32 @external_func(i32 noundef) | ||
|
||
; CHECK-DAG: .csect __llvm_prf_cnts.__profc_func1[RW] | ||
; CHECK-DAG: .csect __llvm_prf_data.__profd_func1[RW] | ||
; CHECK-DAG: .csect __llvm_prf_cnts.__profc_func2[RW] | ||
; CHECK-DAG: .csect __llvm_prf_data.__profd_func2[RW] | ||
; CHECK-DAG: .csect __llvm_prf_names[RO] | ||
|
||
; CHECK: .csect __llvm_prf_cnts.__profc_func1[RW] | ||
; CHECK-NEXT: .ref __llvm_prf_names[RO] | ||
; CHECK-NEXT: .ref __llvm_prf_data.__profd_func1[RW] | ||
; CHECK-NEXT: .rename __llvm_prf_cnts.__profc_func1[RW],"__llvm_prf_cnts" | ||
|
||
; CHECK: .csect __llvm_prf_data.__profd_func1[RW] | ||
; CHECK-NEXT: .rename __llvm_prf_data.__profd_func1[RW],"__llvm_prf_data" | ||
|
||
; CHECK: .csect __llvm_prf_cnts.__profc_func2[RW] | ||
; CHECK-NEXT: .ref __llvm_prf_names[RO] | ||
; CHECK-NEXT: .ref __llvm_prf_data.__profd_func2[RW] | ||
; CHECK-NEXT: .rename __llvm_prf_cnts.__profc_func2[RW],"__llvm_prf_cnts" | ||
|
||
; CHECK: .csect __llvm_prf_data.__profd_func2[RW] | ||
; CHECK-NEXT: .rename __llvm_prf_data.__profd_func2[RW],"__llvm_prf_data" |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we reduce vertical spacing: use single space in some and no space in others