[llvm] 25a8aec - [AIX] ExternalSymbolSDNode lowering
Xiangling Liao via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 14 06:40:25 PST 2020
Author: Xiangling Liao
Date: 2020-01-14T09:39:02-05:00
New Revision: 25a8aec7f37b970849ccf5f2893431e2ca858709
URL: https://github.com/llvm/llvm-project/commit/25a8aec7f37b970849ccf5f2893431e2ca858709
DIFF: https://github.com/llvm/llvm-project/commit/25a8aec7f37b970849ccf5f2893431e2ca858709.diff
LOG: [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
Added:
llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll
llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll
Modified:
llvm/lib/Target/PowerPC/PPCISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 881d6d71a199..60ed72e1018b 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -5117,6 +5117,15 @@ static unsigned getCallOpcode(bool isIndirectCall, bool isPatchPoint,
return PPCISD::CALL;
}
+
+static bool isValidAIXExternalSymSDNode(StringRef SymName) {
+ return StringSwitch<bool>(SymName)
+ .Cases("__divdi3", "__fixunsdfdi", "__floatundidf", "__floatundisf",
+ "__moddi3", "__udivdi3", "__umoddi3", true)
+ .Cases("ceil", "floor", "memcpy", "memmove", "memset", "round", true)
+ .Default(false);
+}
+
static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
const SDLoc &dl, const PPCSubtarget &Subtarget) {
if (!Subtarget.usesFunctionDescriptors() && !Subtarget.isELFv2ABI())
@@ -5141,41 +5150,72 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
Subtarget.is32BitELFABI() && !isLocalCallee() &&
Subtarget.getTargetMachine().getRelocationModel() == Reloc::PIC_;
+ // On AIX, direct function calls reference the symbol for the function's
+ // entry point, which is named by prepending a "." before the function's
+ // C-linkage name.
+ const auto getAIXFuncEntryPointSymbolSDNode =
+ [&](StringRef FuncName, bool IsDeclaration,
+ const XCOFF::StorageClass &SC) {
+ auto &Context = DAG.getMachineFunction().getMMI().getContext();
+
+ MCSymbolXCOFF *S = cast<MCSymbolXCOFF>(
+ Context.getOrCreateSymbol(Twine(".") + Twine(FuncName)));
+
+ if (IsDeclaration && !S->hasContainingCsect()) {
+ // On AIX, an undefined symbol needs to be associated with a
+ // MCSectionXCOFF to get the correct storage mapping class.
+ // In this case, XCOFF::XMC_PR.
+ MCSectionXCOFF *Sec = Context.getXCOFFSection(
+ S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER, SC,
+ SectionKind::getMetadata());
+ S->setContainingCsect(Sec);
+ }
+
+ MVT PtrVT =
+ DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+ return DAG.getMCSymbol(S, PtrVT);
+ };
+
if (isFunctionGlobalAddress(Callee)) {
const GlobalAddressSDNode *G = cast<GlobalAddressSDNode>(Callee);
+ const GlobalValue *GV = G->getGlobal();
+
if (!Subtarget.isAIXABI())
- return DAG.getTargetGlobalAddress(G->getGlobal(), dl,
- Callee.getValueType(), 0,
+ return DAG.getTargetGlobalAddress(GV, dl, Callee.getValueType(), 0,
UsePlt ? PPCII::MO_PLT : 0);
- // On AIX, direct function calls reference the symbol for the function's
- // entry point, which is named by prepending a "." before the function's
- // C-linkage name.
- auto &Context = DAG.getMachineFunction().getMMI().getContext();
+ assert(!isa<GlobalIFunc>(GV) && "IFunc is not supported on AIX.");
+ const GlobalObject *GO = cast<GlobalObject>(GV);
+ const XCOFF::StorageClass SC =
+ TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
+ return getAIXFuncEntryPointSymbolSDNode(GO->getName(), GO->isDeclaration(),
+ SC);
+ }
- const GlobalObject *GO = cast<GlobalObject>(G->getGlobal());
- MCSymbolXCOFF *S = cast<MCSymbolXCOFF>(
- Context.getOrCreateSymbol(Twine(".") + Twine(GO->getName())));
+ if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ const char *SymName = S->getSymbol();
+ if (!Subtarget.isAIXABI())
+ return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(),
+ UsePlt ? PPCII::MO_PLT : 0);
- if (GO && GO->isDeclaration() && !S->hasContainingCsect()) {
- // On AIX, an undefined symbol needs to be associated with a
- // MCSectionXCOFF to get the correct storage mapping class.
- // In this case, XCOFF::XMC_PR.
+ // If there exists a user-declared function whose name is the same as the
+ // ExternalSymbol's, then we pick up the user-declared version.
+ const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
+ if (const Function *F =
+ dyn_cast_or_null<Function>(Mod->getNamedValue(SymName))) {
const XCOFF::StorageClass SC =
- TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
- MCSectionXCOFF *Sec =
- Context.getXCOFFSection(S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER,
- SC, SectionKind::getMetadata());
- S->setContainingCsect(Sec);
+ TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F);
+ return getAIXFuncEntryPointSymbolSDNode(F->getName(), F->isDeclaration(),
+ SC);
}
- EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
- return DAG.getMCSymbol(S, PtrVT);
- }
+ // TODO: Remove this when the support for ExternalSymbolSDNode is complete.
+ if (isValidAIXExternalSymSDNode(SymName)) {
+ return getAIXFuncEntryPointSymbolSDNode(SymName, true, XCOFF::C_EXT);
+ }
- if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
- return DAG.getTargetExternalSymbol(S->getSymbol(), Callee.getValueType(),
- UsePlt ? PPCII::MO_PLT : 0);
+ report_fatal_error("Unexpected ExternalSymbolSDNode: " + Twine(SymName));
+ }
// No transformation needed.
assert(Callee.getNode() && "What no callee?");
diff --git a/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll b/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll
new file mode 100644
index 000000000000..f5864df4ff95
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll
@@ -0,0 +1,128 @@
+; RUN: llc -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -stop-after=machine-cp < %s | FileCheck \
+; RUN: --check-prefix=32BIT %s
+
+; RUN: llc -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \
+; RUN: -stop-after=machine-cp < %s | FileCheck \
+; RUN: --check-prefix=64BIT %s
+
+define i64 @call_divdi3(i64 %p, i64 %num) {
+entry:
+ %div = sdiv i64 %p, %num
+ ret i64 %div
+}
+
+; 32BIT: BL_NOP <mcsymbol .__divdi3>
+
+define i64 @call_fixunsdfdi(double %p) {
+entry:
+ %conv = fptoui double %p to i64
+ ret i64 %conv
+}
+
+; 32BIT: BL_NOP <mcsymbol .__fixunsdfdi>
+
+define double @call_floatundidf(i64 %p) {
+entry:
+ %conv = uitofp i64 %p to double
+ ret double %conv
+}
+
+; 32BIT: BL_NOP <mcsymbol .__floatundidf>
+
+define float @call_floatundisf(i64 %p) {
+entry:
+ %conv = uitofp i64 %p to float
+ ret float %conv
+}
+
+; 32BIT: BL_NOP <mcsymbol .__floatundisf>
+
+define i64 @call_moddi3(i64 %p, i64 %num) {
+entry:
+ %rem = srem i64 %p, %num
+ ret i64 %rem
+}
+
+; 32BIT: BL_NOP <mcsymbol .__moddi3>
+
+define i64 @call_udivdi3(i64 %p, i64 %q) {
+ %1 = udiv i64 %p, %q
+ ret i64 %1
+}
+
+; 32BIT: BL_NOP <mcsymbol .__udivdi3>
+
+define i64 @call_umoddi3(i64 %p, i64 %num) {
+entry:
+ %rem = urem i64 %p, %num
+ ret i64 %rem
+}
+
+; 32BIT: BL_NOP <mcsymbol .__umoddi3>
+
+define double @call_ceil(double %n) {
+entry:
+ %0 = call double @llvm.ceil.f64(double %n)
+ ret double %0
+}
+
+declare double @llvm.ceil.f64(double)
+
+; 32BIT: BL_NOP <mcsymbol .ceil>
+; 64BIT: BL8_NOP <mcsymbol .ceil>
+
+define double @call_floor(double %n) {
+entry:
+ %0 = call double @llvm.floor.f64(double %n)
+ ret double %0
+}
+
+declare double @llvm.floor.f64(double)
+
+; 32BIT: BL_NOP <mcsymbol .floor>
+; 64BIT: BL8_NOP <mcsymbol .floor>
+
+define void @call_memcpy(i8* %p, i8* %q, i32 %n) {
+entry:
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
+ ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1)
+
+; 32BIT: BL_NOP <mcsymbol .memcpy>
+; 64BIT: BL8_NOP <mcsymbol .memcpy>
+
+define void @call_memmove(i8* %p, i8* %q, i32 %n) {
+entry:
+ call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
+ ret void
+}
+
+declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1)
+
+; 32BIT: BL_NOP <mcsymbol .memmove>
+; 64BIT: BL8_NOP <mcsymbol .memmove>
+
+define void @call_memset(i8* %p, i8 %q, i32 %n) #0 {
+entry:
+ call void @llvm.memset.p0i8.i32(i8* %p, i8 %q, i32 %n, i1 false)
+ ret void
+}
+
+declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i1)
+
+; 32BIT: BL_NOP <mcsymbol .memset>
+; 64BIT: BL8_NOP <mcsymbol .memset>
+
+define double @call_round(double %n) {
+entry:
+ %0 = call double @llvm.round.f64(double %n)
+ ret double %0
+}
+
+declare double @llvm.round.f64(double)
+
+; 32BIT: BL_NOP <mcsymbol .round>
+; 64BIT: BL8_NOP <mcsymbol .round>
diff --git a/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll b/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll
new file mode 100644
index 000000000000..0b892a3ded61
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll
@@ -0,0 +1,58 @@
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \
+; RUN: -mattr=-altivec -filetype=obj -o %t.o < %s
+
+; RUN: llvm-readobj --syms %t.o | FileCheck --check-prefix=32-SYM %s
+
+; RUN: llvm-readobj --relocs --expand-relocs %t.o | FileCheck \
+; RUN: --check-prefix=32-REL %s
+
+; RUN: not llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \
+; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj < %s 2>&1 | FileCheck \
+; RUN: --check-prefix=64-CHECK %s
+
+; Test verifies:
+; If there exists a user-defined function whose name is the same as the
+; "memcpy" ExternalSymbol's, we pick up the user-defined version, even if this
+; may lead to some undefined behavior.
+
+define dso_local signext i32 @memcpy(i8* %destination, i32 signext %num) {
+entry:
+ ret i32 3
+}
+
+define void @call_memcpy(i8* %p, i8* %q, i32 %n) {
+entry:
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i1 false)
+ ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1)
+
+; TODO: This test should preferably check the symbol table for .o file and
+; the relocation associated with the call.
+
+; 32-SYM: Symbol {{[{][[:space:]] *}}Index: [[#Index:]]{{[[:space:]] *}}Name: .memcpy
+; 32-SYM-NEXT: Value (RelocatableAddress): 0x0
+; 32-SYM-NEXT: Section: .text
+; 32-SYM-NEXT: Type: 0x0
+; 32-SYM-NEXT: StorageClass: C_EXT (0x2)
+; 32-SYM-NEXT: NumberOfAuxEntries: 1
+; 32-SYM-NEXT: CSECT Auxiliary Entry {
+; 32-SYM-NEXT: Index: 3
+; 32-SYM-NEXT: ContainingCsectSymbolIndex: 0
+; 32-SYM-NEXT: ParameterHashIndex: 0x0
+; 32-SYM-NEXT: TypeChkSectNum: 0x0
+; 32-SYM-NEXT: SymbolAlignmentLog2: 0
+; 32-SYM-NEXT: SymbolType: XTY_LD (0x2)
+; 32-SYM-NEXT: StorageMappingClass: XMC_PR (0x0)
+; 32-SYM-NEXT: StabInfoIndex: 0x0
+; 32-SYM-NEXT: StabSectNum: 0x0
+; 32-SYM-NEXT: }
+; 32-SYM-NEXT: }
+
+; 32-SYM-NOT: .memcpy
+
+; We are expecting to have the test fail when the support for relocations land.
+; 32-REL-NOT: Relocation{{[[:space:]]}}
+
+; 64-CHECK: LLVM ERROR: 64-bit XCOFF object files are not supported yet.
More information about the llvm-commits
mailing list