Skip to content

Commit 25a8aec

Browse files
committed
[AIX] ExternalSymbolSDNode lowering
For memcpy/memset/memmove etc., replace ExternalSymbolSDNode with a MCSymbolSDNode, which have a prefix dot before function name as entry point symbol. Differential Revision: https://reviews.llvm.org/D70718
1 parent 4b5bc38 commit 25a8aec

File tree

3 files changed

+250
-24
lines changed

3 files changed

+250
-24
lines changed

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5117,6 +5117,15 @@ static unsigned getCallOpcode(bool isIndirectCall, bool isPatchPoint,
51175117

51185118
return PPCISD::CALL;
51195119
}
5120+
5121+
static bool isValidAIXExternalSymSDNode(StringRef SymName) {
5122+
return StringSwitch<bool>(SymName)
5123+
.Cases("__divdi3", "__fixunsdfdi", "__floatundidf", "__floatundisf",
5124+
"__moddi3", "__udivdi3", "__umoddi3", true)
5125+
.Cases("ceil", "floor", "memcpy", "memmove", "memset", "round", true)
5126+
.Default(false);
5127+
}
5128+
51205129
static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
51215130
const SDLoc &dl, const PPCSubtarget &Subtarget) {
51225131
if (!Subtarget.usesFunctionDescriptors() && !Subtarget.isELFv2ABI())
@@ -5141,41 +5150,72 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
51415150
Subtarget.is32BitELFABI() && !isLocalCallee() &&
51425151
Subtarget.getTargetMachine().getRelocationModel() == Reloc::PIC_;
51435152

5153+
// On AIX, direct function calls reference the symbol for the function's
5154+
// entry point, which is named by prepending a "." before the function's
5155+
// C-linkage name.
5156+
const auto getAIXFuncEntryPointSymbolSDNode =
5157+
[&](StringRef FuncName, bool IsDeclaration,
5158+
const XCOFF::StorageClass &SC) {
5159+
auto &Context = DAG.getMachineFunction().getMMI().getContext();
5160+
5161+
MCSymbolXCOFF *S = cast<MCSymbolXCOFF>(
5162+
Context.getOrCreateSymbol(Twine(".") + Twine(FuncName)));
5163+
5164+
if (IsDeclaration && !S->hasContainingCsect()) {
5165+
// On AIX, an undefined symbol needs to be associated with a
5166+
// MCSectionXCOFF to get the correct storage mapping class.
5167+
// In this case, XCOFF::XMC_PR.
5168+
MCSectionXCOFF *Sec = Context.getXCOFFSection(
5169+
S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER, SC,
5170+
SectionKind::getMetadata());
5171+
S->setContainingCsect(Sec);
5172+
}
5173+
5174+
MVT PtrVT =
5175+
DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
5176+
return DAG.getMCSymbol(S, PtrVT);
5177+
};
5178+
51445179
if (isFunctionGlobalAddress(Callee)) {
51455180
const GlobalAddressSDNode *G = cast<GlobalAddressSDNode>(Callee);
5181+
const GlobalValue *GV = G->getGlobal();
5182+
51465183
if (!Subtarget.isAIXABI())
5147-
return DAG.getTargetGlobalAddress(G->getGlobal(), dl,
5148-
Callee.getValueType(), 0,
5184+
return DAG.getTargetGlobalAddress(GV, dl, Callee.getValueType(), 0,
51495185
UsePlt ? PPCII::MO_PLT : 0);
51505186

5151-
// On AIX, direct function calls reference the symbol for the function's
5152-
// entry point, which is named by prepending a "." before the function's
5153-
// C-linkage name.
5154-
auto &Context = DAG.getMachineFunction().getMMI().getContext();
5187+
assert(!isa<GlobalIFunc>(GV) && "IFunc is not supported on AIX.");
5188+
const GlobalObject *GO = cast<GlobalObject>(GV);
5189+
const XCOFF::StorageClass SC =
5190+
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
5191+
return getAIXFuncEntryPointSymbolSDNode(GO->getName(), GO->isDeclaration(),
5192+
SC);
5193+
}
51555194

5156-
const GlobalObject *GO = cast<GlobalObject>(G->getGlobal());
5157-
MCSymbolXCOFF *S = cast<MCSymbolXCOFF>(
5158-
Context.getOrCreateSymbol(Twine(".") + Twine(GO->getName())));
5195+
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
5196+
const char *SymName = S->getSymbol();
5197+
if (!Subtarget.isAIXABI())
5198+
return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(),
5199+
UsePlt ? PPCII::MO_PLT : 0);
51595200

5160-
if (GO && GO->isDeclaration() && !S->hasContainingCsect()) {
5161-
// On AIX, an undefined symbol needs to be associated with a
5162-
// MCSectionXCOFF to get the correct storage mapping class.
5163-
// In this case, XCOFF::XMC_PR.
5201+
// If there exists a user-declared function whose name is the same as the
5202+
// ExternalSymbol's, then we pick up the user-declared version.
5203+
const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
5204+
if (const Function *F =
5205+
dyn_cast_or_null<Function>(Mod->getNamedValue(SymName))) {
51645206
const XCOFF::StorageClass SC =
5165-
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
5166-
MCSectionXCOFF *Sec =
5167-
Context.getXCOFFSection(S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER,
5168-
SC, SectionKind::getMetadata());
5169-
S->setContainingCsect(Sec);
5207+
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F);
5208+
return getAIXFuncEntryPointSymbolSDNode(F->getName(), F->isDeclaration(),
5209+
SC);
51705210
}
51715211

5172-
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
5173-
return DAG.getMCSymbol(S, PtrVT);
5174-
}
5212+
// TODO: Remove this when the support for ExternalSymbolSDNode is complete.
5213+
if (isValidAIXExternalSymSDNode(SymName)) {
5214+
return getAIXFuncEntryPointSymbolSDNode(SymName, true, XCOFF::C_EXT);
5215+
}
51755216

5176-
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
5177-
return DAG.getTargetExternalSymbol(S->getSymbol(), Callee.getValueType(),
5178-
UsePlt ? PPCII::MO_PLT : 0);
5217+
report_fatal_error("Unexpected ExternalSymbolSDNode: " + Twine(SymName));
5218+
}
51795219

51805220
// No transformation needed.
51815221
assert(Callee.getNode() && "What no callee?");
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
; RUN: llc -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \
2+
; RUN: -stop-after=machine-cp < %s | FileCheck \
3+
; RUN: --check-prefix=32BIT %s
4+
5+
; RUN: llc -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \
6+
; RUN: -stop-after=machine-cp < %s | FileCheck \
7+
; RUN: --check-prefix=64BIT %s
8+
9+
define i64 @call_divdi3(i64 %p, i64 %num) {
10+
entry:
11+
%div = sdiv i64 %p, %num
12+
ret i64 %div
13+
}
14+
15+
; 32BIT: BL_NOP <mcsymbol .__divdi3>
16+
17+
define i64 @call_fixunsdfdi(double %p) {
18+
entry:
19+
%conv = fptoui double %p to i64
20+
ret i64 %conv
21+
}
22+
23+
; 32BIT: BL_NOP <mcsymbol .__fixunsdfdi>
24+
25+
define double @call_floatundidf(i64 %p) {
26+
entry:
27+
%conv = uitofp i64 %p to double
28+
ret double %conv
29+
}
30+
31+
; 32BIT: BL_NOP <mcsymbol .__floatundidf>
32+
33+
define float @call_floatundisf(i64 %p) {
34+
entry:
35+
%conv = uitofp i64 %p to float
36+
ret float %conv
37+
}
38+
39+
; 32BIT: BL_NOP <mcsymbol .__floatundisf>
40+
41+
define i64 @call_moddi3(i64 %p, i64 %num) {
42+
entry:
43+
%rem = srem i64 %p, %num
44+
ret i64 %rem
45+
}
46+
47+
; 32BIT: BL_NOP <mcsymbol .__moddi3>
48+
49+
define i64 @call_udivdi3(i64 %p, i64 %q) {
50+
%1 = udiv i64 %p, %q
51+
ret i64 %1
52+
}
53+
54+
; 32BIT: BL_NOP <mcsymbol .__udivdi3>
55+
56+
define i64 @call_umoddi3(i64 %p, i64 %num) {
57+
entry:
58+
%rem = urem i64 %p, %num
59+
ret i64 %rem
60+
}
61+
62+
; 32BIT: BL_NOP <mcsymbol .__umoddi3>
63+
64+
define double @call_ceil(double %n) {
65+
entry:
66+
%0 = call double @llvm.ceil.f64(double %n)
67+
ret double %0
68+
}
69+
70+
declare double @llvm.ceil.f64(double)
71+
72+
; 32BIT: BL_NOP <mcsymbol .ceil>
73+
; 64BIT: BL8_NOP <mcsymbol .ceil>
74+
75+
define double @call_floor(double %n) {
76+
entry:
77+
%0 = call double @llvm.floor.f64(double %n)
78+
ret double %0
79+
}
80+
81+
declare double @llvm.floor.f64(double)
82+
83+
; 32BIT: BL_NOP <mcsymbol .floor>
84+
; 64BIT: BL8_NOP <mcsymbol .floor>
85+
86+
define void @call_memcpy(i8* %p, i8* %q, i32 %n) {
87+
entry:
88+
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
89+
ret void
90+
}
91+
92+
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1)
93+
94+
; 32BIT: BL_NOP <mcsymbol .memcpy>
95+
; 64BIT: BL8_NOP <mcsymbol .memcpy>
96+
97+
define void @call_memmove(i8* %p, i8* %q, i32 %n) {
98+
entry:
99+
call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
100+
ret void
101+
}
102+
103+
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1)
104+
105+
; 32BIT: BL_NOP <mcsymbol .memmove>
106+
; 64BIT: BL8_NOP <mcsymbol .memmove>
107+
108+
define void @call_memset(i8* %p, i8 %q, i32 %n) #0 {
109+
entry:
110+
call void @llvm.memset.p0i8.i32(i8* %p, i8 %q, i32 %n, i1 false)
111+
ret void
112+
}
113+
114+
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i1)
115+
116+
; 32BIT: BL_NOP <mcsymbol .memset>
117+
; 64BIT: BL8_NOP <mcsymbol .memset>
118+
119+
define double @call_round(double %n) {
120+
entry:
121+
%0 = call double @llvm.round.f64(double %n)
122+
ret double %0
123+
}
124+
125+
declare double @llvm.round.f64(double)
126+
127+
; 32BIT: BL_NOP <mcsymbol .round>
128+
; 64BIT: BL8_NOP <mcsymbol .round>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \
2+
; RUN: -mattr=-altivec -filetype=obj -o %t.o < %s
3+
4+
; RUN: llvm-readobj --syms %t.o | FileCheck --check-prefix=32-SYM %s
5+
6+
; RUN: llvm-readobj --relocs --expand-relocs %t.o | FileCheck \
7+
; RUN: --check-prefix=32-REL %s
8+
9+
; RUN: not llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \
10+
; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj < %s 2>&1 | FileCheck \
11+
; RUN: --check-prefix=64-CHECK %s
12+
13+
; Test verifies:
14+
; If there exists a user-defined function whose name is the same as the
15+
; "memcpy" ExternalSymbol's, we pick up the user-defined version, even if this
16+
; may lead to some undefined behavior.
17+
18+
define dso_local signext i32 @memcpy(i8* %destination, i32 signext %num) {
19+
entry:
20+
ret i32 3
21+
}
22+
23+
define void @call_memcpy(i8* %p, i8* %q, i32 %n) {
24+
entry:
25+
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
26+
ret void
27+
}
28+
29+
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1)
30+
31+
; TODO: This test should preferably check the symbol table for .o file and
32+
; the relocation associated with the call.
33+
34+
; 32-SYM: Symbol {{[{][[:space:]] *}}Index: [[#Index:]]{{[[:space:]] *}}Name: .memcpy
35+
; 32-SYM-NEXT: Value (RelocatableAddress): 0x0
36+
; 32-SYM-NEXT: Section: .text
37+
; 32-SYM-NEXT: Type: 0x0
38+
; 32-SYM-NEXT: StorageClass: C_EXT (0x2)
39+
; 32-SYM-NEXT: NumberOfAuxEntries: 1
40+
; 32-SYM-NEXT: CSECT Auxiliary Entry {
41+
; 32-SYM-NEXT: Index: 3
42+
; 32-SYM-NEXT: ContainingCsectSymbolIndex: 0
43+
; 32-SYM-NEXT: ParameterHashIndex: 0x0
44+
; 32-SYM-NEXT: TypeChkSectNum: 0x0
45+
; 32-SYM-NEXT: SymbolAlignmentLog2: 0
46+
; 32-SYM-NEXT: SymbolType: XTY_LD (0x2)
47+
; 32-SYM-NEXT: StorageMappingClass: XMC_PR (0x0)
48+
; 32-SYM-NEXT: StabInfoIndex: 0x0
49+
; 32-SYM-NEXT: StabSectNum: 0x0
50+
; 32-SYM-NEXT: }
51+
; 32-SYM-NEXT: }
52+
53+
; 32-SYM-NOT: .memcpy
54+
55+
; We are expecting to have the test fail when the support for relocations land.
56+
; 32-REL-NOT: Relocation{{[[:space:]]}}
57+
58+
; 64-CHECK: LLVM ERROR: 64-bit XCOFF object files are not supported yet.

0 commit comments

Comments
 (0)