Skip to content

[AIX] [XCOFF] Add support for common and local common symbols in the TOC #79530

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 4 commits into from
Jan 31, 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
4 changes: 3 additions & 1 deletion llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2424,8 +2424,10 @@ MCSection *TargetLoweringObjectFileXCOFF::SelectSectionForGlobal(
if (GVar->hasAttribute("toc-data")) {
SmallString<128> Name;
getNameWithPrefix(Name, GO, TM);
XCOFF::SymbolType symType =
GO->hasCommonLinkage() ? XCOFF::XTY_CM : XCOFF::XTY_SD;
return getContext().getXCOFFSection(
Name, Kind, XCOFF::CsectProperties(XCOFF::XMC_TD, XCOFF::XTY_SD),
Name, Kind, XCOFF::CsectProperties(XCOFF::XMC_TD, symType),
/* MultiSymbolsAllowed*/ true);
}

Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/MC/MCSectionXCOFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ void MCSectionXCOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
}

if (isCsect() && getMappingClass() == XCOFF::XMC_TD) {
// Common csect type (uninitialized storage) does not have to print csect
// directive for section switching unless it is local.
if (getKind().isCommon() && !getKind().isBSSLocal())
return;

assert((getKind().isBSSExtern() || getKind().isBSSLocal()) &&
"Unexepected section kind for toc-data");
printCsectDirective(OS);
Expand Down Expand Up @@ -135,5 +140,7 @@ bool MCSectionXCOFF::isVirtualSection() const {
return false;
assert(isCsect() &&
"Handling for isVirtualSection not implemented for this section!");
return XCOFF::XTY_CM == CsectProp->Type;
// XTY_CM sections are virtual except for toc-data symbols.
return (XCOFF::XTY_CM == CsectProp->Type) &&
(getMappingClass() != XCOFF::XMC_TD);
}
10 changes: 8 additions & 2 deletions llvm/lib/MC/XCOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,15 @@ CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
return TOCCsects;
case XCOFF::XMC_TC:
case XCOFF::XMC_TE:
case XCOFF::XMC_TD:
assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
"Only an initialized csect can contain TC entry.");
"A TOC symbol must be an initialized csect.");
assert(!TOCCsects.empty() &&
"We should at least have a TOC-base in this CsectGroup.");
return TOCCsects;
case XCOFF::XMC_TD:
assert((XCOFF::XTY_SD == MCSec->getCSectType() ||
XCOFF::XTY_CM == MCSec->getCSectType()) &&
"Symbol type incompatible with toc-data.");
assert(!TOCCsects.empty() &&
"We should at least have a TOC-base in this CsectGroup.");
return TOCCsects;
Expand Down
23 changes: 19 additions & 4 deletions llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2571,12 +2571,18 @@ void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) {
GVSym->setStorageClass(
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV));

if (GVKind.isBSSLocal() || GVKind.isThreadBSSLocal())
if (GVKind.isBSSLocal() && Csect->getMappingClass() == XCOFF::XMC_TD) {
OutStreamer->emitZeros(Size);
} else if (GVKind.isBSSLocal() || GVKind.isThreadBSSLocal()) {
assert(Csect->getMappingClass() != XCOFF::XMC_TD &&
"BSS local toc-data already handled and TLS variables "
"incompatible with XMC_TD");
OutStreamer->emitXCOFFLocalCommonSymbol(
OutContext.getOrCreateSymbol(GVSym->getSymbolTableName()), Size,
GVSym, Alignment);
else
} else {
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
}
return;
}

Expand Down Expand Up @@ -2737,8 +2743,17 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
TS->emitTCEntry(*I.first.first, I.first.second);
}

for (const auto *GV : TOCDataGlobalVars)
emitGlobalVariableHelper(GV);
// Traverse the list of global variables twice, emitting all of the
// non-common global variables before the common ones, as emitting a
// .comm directive changes the scope from .toc to the common symbol.
for (const auto *GV : TOCDataGlobalVars) {
if (!GV->hasCommonLinkage())
emitGlobalVariableHelper(GV);
}
for (const auto *GV : TOCDataGlobalVars) {
if (GV->hasCommonLinkage())
emitGlobalVariableHelper(GV);
}
}

bool PPCAIXAsmPrinter::doInitialization(Module &M) {
Expand Down
7 changes: 2 additions & 5 deletions llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,13 +551,10 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
"A GlobalVariable with size larger than a TOC entry is not currently "
"supported by the toc data transformation.");

if (GV->hasLocalLinkage() || GV->hasPrivateLinkage())
report_fatal_error("A GlobalVariable with private or local linkage is not "
if (GV->hasPrivateLinkage())
report_fatal_error("A GlobalVariable with private linkage is not "
"currently supported by the toc data transformation.");

assert(!GV->hasCommonLinkage() &&
"Tentative definitions cannot have the mapping class XMC_TD.");

return true;
}

Expand Down
10 changes: 6 additions & 4 deletions llvm/test/CodeGen/PowerPC/basic-toc-data-local-linkage.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs \
; RUN: llc -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs \
; RUN: < %s 2>&1 | FileCheck %s
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs \
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs \
; RUN: < %s 2>&1 | FileCheck %s

@ilocal = internal global i32 0, align 4 #0
Expand All @@ -11,6 +11,8 @@ define dso_local i32 @read_i32_local_linkage() {
ret i32 %0
}

; CHECK: LLVM ERROR: A GlobalVariable with private or local linkage is not currently supported by the toc data transformation.

attributes #0 = { "toc-data" }

; CHECK: .toc
; CHECK-NEXT: .csect ilocal[TD],2
; CHECK-NEXT: .space 4
15 changes: 15 additions & 0 deletions llvm/test/CodeGen/PowerPC/basic-toc-data-private-linkage.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs \
; RUN: < %s 2>&1 | FileCheck %s
; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs \
; RUN: < %s 2>&1 | FileCheck %s

@iprivate = private global i32 55 #0

define nonnull ptr @get() local_unnamed_addr {
entry:
ret ptr @iprivate
}

attributes #0 = { "toc-data" }

; CHECK: LLVM ERROR: A GlobalVariable with private linkage is not currently supported by the toc data transformation.
148 changes: 148 additions & 0 deletions llvm/test/CodeGen/PowerPC/toc-data-common.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs < %s | FileCheck %s -DINSTR=lwz --check-prefix=CHECK
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs < %s | FileCheck %s -DINSTR=ld --check-prefix=CHECK

; RUN: llc -filetype=obj -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs < %s -o %t32.o
; RUN: llvm-objdump -t --symbol-description %t32.o | FileCheck %s --check-prefix=OBJ32

; RUN: llc -filetype=obj -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs < %s -o %t64.o
; RUN: llvm-objdump -t --symbol-description %t64.o | FileCheck %s --check-prefix=OBJ64

@a1 = common global i32 0, align 4 #0
@a2 = global i32 0, align 4 #0
@a3 = common global i32 0, align 4
@a4 = global i32 0, align 4

define void @set(i32 noundef %_a) {
; CHECK-LABEL: set:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: la 4, a2[TD](2)
; CHECK-NEXT: la 5, a1[TD](2)
; CHECK-NEXT: stw 3, 0(4)
; CHECK-NEXT: [[INSTR]] 4, L..C0(2) # @a4
; CHECK-NEXT: stw 3, 0(5)
; CHECK-NEXT: [[INSTR]] 5, L..C1(2) # @a3
; CHECK-NEXT: stw 3, 0(4)
; CHECK-NEXT: stw 3, 0(5)
; CHECK-NEXT: blr
entry:
store i32 %_a, ptr @a2, align 4
store i32 %_a, ptr @a1, align 4
store i32 %_a, ptr @a4, align 4
store i32 %_a, ptr @a3, align 4
ret void
}

define i32 @get1() {
; CHECK-LABEL: get1:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: la 3, a2[TD](2)
; CHECK-NEXT: lwz 3, 0(3)
; CHECK-NEXT: blr
entry:
%0 = load i32, ptr @a2, align 4
ret i32 %0
}

define i32 @get2() {
; CHECK-LABEL: get2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: la 3, a1[TD](2)
; CHECK-NEXT: lwz 3, 0(3)
; CHECK-NEXT: blr
entry:
%0 = load i32, ptr @a1, align 4
ret i32 %0
}

define i32 @get3() {
; CHECK-LABEL: get3:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: [[INSTR]] 3, L..C0(2) # @a4
; CHECK-NEXT: lwz 3, 0(3)
; CHECK-NEXT: blr
entry:
%0 = load i32, ptr @a4, align 4
ret i32 %0
}

define i32 @get4() {
; CHECK-LABEL: get4:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: [[INSTR]] 3, L..C1(2) # @a3
; CHECK-NEXT: lwz 3, 0(3)
; CHECK-NEXT: blr
entry:
%0 = load i32, ptr @a3, align 4
ret i32 %0
}

define nonnull ptr @escape1() {
; CHECK-LABEL: escape1:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: la 3, a2[TD](2)
; CHECK-NEXT: blr
entry:
ret ptr @a2
}

define nonnull ptr @escape2() {
; CHECK-LABEL: escape2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: la 3, a1[TD](2)
; CHECK-NEXT: blr
entry:
ret ptr @a1
}

define nonnull ptr @escape3() {
; CHECK-LABEL: escape3:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: [[INSTR]] 3, L..C0(2) # @a4
; CHECK-NEXT: blr
entry:
ret ptr @a4
}

define nonnull ptr @escape4() {
; CHECK-LABEL: escape4:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: [[INSTR]] 3, L..C1(2) # @a3
; CHECK-NEXT: blr
entry:
ret ptr @a3
}

attributes #0 = { "toc-data" }

; CHECK: .comm a3[RW],4,2 # @a3
; CHECK-NEXT: .csect a4[RW],2
; CHECK-NEXT: .globl a4[RW] # @a4
; CHECK-NEXT: .align 2
; CHECK-NEXT: .vbyte 4, 0 # 0x0
; CHECK-NEXT: .toc
; CHECK-LABEL: L..C0:
; CHECK-NEXT: .tc a4[TC],a4[RW]
; CHECK-LABEL: L..C1:
; CHECK-NEXT: .tc a3[TC],a3[RW]
; CHECK-NEXT: .csect a2[TD],2
; CHECK-NEXT: .globl a2[TD] # @a2
; CHECK-NEXT: .align 2
; CHECK-NEXT: .vbyte 4, 0 # 0x0
; CHECK-NEXT: .comm a1[TD],4,2 # @a1

; OBJ32: {{([[:xdigit:]]{8})}} g O .data 00000004 (idx: {{[0-9]+}}) a4[RW]
; OBJ32-LABEL: {{([[:xdigit:]]{8})}} l .data 00000000 (idx: {{[0-9]+}}) TOC[TC0]
; OBJ32-NEXT: {{([[:xdigit:]]{8})}} l O .data 00000004 (idx: {{[0-9]+}}) a4[TC]
; OBJ32-NEXT: {{([[:xdigit:]]{8})}} l O .data 00000004 (idx: {{[0-9]+}}) a3[TC]
; OBJ32-NEXT: {{([[:xdigit:]]{8})}} g O .data 00000004 (idx: {{[0-9]+}}) a2[TD]
; OBJ32-NEXT: {{([[:xdigit:]]{8})}} g O *COM* 00000004 (idx: {{[0-9]+}}) a1[TD]
; OBJ32-NEXT: {{([[:xdigit:]]{8})}} g O *COM* 00000004 (idx: {{[0-9]+}}) a3[RW]

; OBJ64: {{([[:xdigit:]]{16})}} g O .data 0000000000000004 (idx: {{[0-9]+}}) a4[RW]
; OBJ64-LABEL: {{([[:xdigit:]]{16})}} l .data 0000000000000000 (idx: {{[0-9]+}}) TOC[TC0]
; OBJ64-NEXT: {{([[:xdigit:]]{16})}} l O .data 0000000000000008 (idx: {{[0-9]+}}) a4[TC]
; OBJ64-NEXT: {{([[:xdigit:]]{16})}} l O .data 0000000000000008 (idx: {{[0-9]+}}) a3[TC]
; OBJ64-NEXT: {{([[:xdigit:]]{16})}} g O .data 0000000000000004 (idx: {{[0-9]+}}) a2[TD]
; OBJ64-NEXT: {{([[:xdigit:]]{16})}} g O *COM* 0000000000000004 (idx: {{[0-9]+}}) a1[TD]
; OBJ64-NEXT: {{([[:xdigit:]]{16})}} g O *COM* 0000000000000004 (idx: {{[0-9]+}}) a3[RW]