Skip to content

Commit 1154689

Browse files
author
diggerlin
committed
[AIX][XCOFF]emit extern linkage for the llvm intrinsic symbol
SUMMARY: when we call memset, memcopy,memmove etc(this are llvm intrinsic function) in the c source code. the llvm will generate IR like call call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (%struct.S* @s to i8*), i8 %1, i32 %2, i1 false) for c source code bash> cat test_memset.call struct S{ int a; int b; }; extern struct S s; void bar() { memset(&s, s.b, s.b); } like %struct.S = type { i32, i32 } @s = external global %struct.S, align 4 ; Function Attrs: noinline nounwind optnone define void @bar() #0 { entry: %0 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 %1 = trunc i32 %0 to i8 %2 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (%struct.S* @s to i8*), i8 %1, i32 %2, i1 false) ret void } declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) #1 If we want to let the aix as assembly compile pass without -u it need to has following assembly code. .extern .memset (we do not output extern linkage for llvm instrinsic function. even if we output the extern linkage for llvm intrinsic function, we should not out .extern llvm.memset.p0i8.i32, instead of we should emit .extern memset) for other llvm buildin function floatdidf . even if we do not call these function floatdidf in the c source code(the generated IR also do not the call __floatdidf . the function call was generated in the LLVM optimized. the function is not in the functions list of Module, but we still need to emit extern .__floatdidf The solution for it as : We record all the lllvm intrinsic extern symbol when transformCallee(), and emit all these symbol in the AsmPrinter::doFinalization(Module &M) Reviewers: jasonliu, Sean Fertile, hubert.reinterpretcast, Differential Revision: https://reviews.llvm.org/D78929
1 parent 73bc23f commit 1154689

7 files changed

+168
-25
lines changed

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "PPCTargetStreamer.h"
2828
#include "TargetInfo/PowerPCTargetInfo.h"
2929
#include "llvm/ADT/MapVector.h"
30+
#include "llvm/ADT/SmallPtrSet.h"
3031
#include "llvm/ADT/StringRef.h"
3132
#include "llvm/ADT/Triple.h"
3233
#include "llvm/ADT/Twine.h"
@@ -47,6 +48,7 @@
4748
#include "llvm/IR/Module.h"
4849
#include "llvm/MC/MCAsmInfo.h"
4950
#include "llvm/MC/MCContext.h"
51+
#include "llvm/MC/MCDirectives.h"
5052
#include "llvm/MC/MCExpr.h"
5153
#include "llvm/MC/MCInst.h"
5254
#include "llvm/MC/MCInstBuilder.h"
@@ -147,6 +149,10 @@ class PPCLinuxAsmPrinter : public PPCAsmPrinter {
147149

148150
class PPCAIXAsmPrinter : public PPCAsmPrinter {
149151
private:
152+
/// Symbols lowered from ExternalSymbolSDNodes, we will need to emit extern
153+
/// linkage for them in AIX.
154+
SmallPtrSet<MCSymbol *, 8> ExtSymSDNodeSymbols;
155+
150156
static void ValidateGV(const GlobalVariable *GV);
151157

152158
public:
@@ -170,6 +176,10 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
170176
void emitEndOfAsmFile(Module &) override;
171177

172178
void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override;
179+
180+
void emitInstruction(const MachineInstr *MI) override;
181+
182+
bool doFinalization(Module &M) override;
173183
};
174184

175185
} // end anonymous namespace
@@ -1812,6 +1822,55 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
18121822
return Result;
18131823
}
18141824

1825+
void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) {
1826+
switch (MI->getOpcode()) {
1827+
default:
1828+
break;
1829+
case PPC::BL8:
1830+
case PPC::BL:
1831+
case PPC::BL8_NOP:
1832+
case PPC::BL_NOP: {
1833+
const MachineOperand &MO = MI->getOperand(0);
1834+
if (MO.isSymbol()) {
1835+
MCSymbolXCOFF *S =
1836+
cast<MCSymbolXCOFF>(OutContext.getOrCreateSymbol(MO.getSymbolName()));
1837+
if (!S->hasRepresentedCsectSet()) {
1838+
// On AIX, an undefined symbol needs to be associated with a
1839+
// MCSectionXCOFF to get the correct storage mapping class.
1840+
// In this case, XCOFF::XMC_PR.
1841+
MCSectionXCOFF *Sec = OutContext.getXCOFFSection(
1842+
S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER, XCOFF::C_EXT,
1843+
SectionKind::getMetadata());
1844+
S->setRepresentedCsect(Sec);
1845+
}
1846+
ExtSymSDNodeSymbols.insert(S);
1847+
}
1848+
} break;
1849+
case PPC::BL_TLS:
1850+
case PPC::BL8_TLS:
1851+
case PPC::BL8_TLS_:
1852+
case PPC::BL8_NOP_TLS:
1853+
report_fatal_error("TLS call not yet implemented");
1854+
case PPC::TAILB:
1855+
case PPC::TAILB8:
1856+
case PPC::TAILBA:
1857+
case PPC::TAILBA8:
1858+
case PPC::TAILBCTR:
1859+
case PPC::TAILBCTR8:
1860+
if (MI->getOperand(0).isSymbol())
1861+
report_fatal_error("Tail call for extern symbol not yet supported.");
1862+
break;
1863+
}
1864+
return PPCAsmPrinter::emitInstruction(MI);
1865+
}
1866+
1867+
bool PPCAIXAsmPrinter::doFinalization(Module &M) {
1868+
bool Ret = PPCAsmPrinter::doFinalization(M);
1869+
for (MCSymbol *Sym : ExtSymSDNodeSymbols)
1870+
OutStreamer->emitSymbolAttribute(Sym, MCSA_Extern);
1871+
return Ret;
1872+
}
1873+
18151874
/// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
18161875
/// for a MachineFunction to the given output stream, in a format that the
18171876
/// Darwin assembler can deal with.

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

+22-18
Original file line numberDiff line numberDiff line change
@@ -5335,13 +5335,18 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
53355335
// On AIX, direct function calls reference the symbol for the function's
53365336
// entry point, which is named by prepending a "." before the function's
53375337
// C-linkage name.
5338+
const auto getFunctionEntryPointSymbol = [&](StringRef SymName) {
5339+
auto &Context = DAG.getMachineFunction().getMMI().getContext();
5340+
return cast<MCSymbolXCOFF>(
5341+
Context.getOrCreateSymbol(Twine(".") + Twine(SymName)));
5342+
};
5343+
53385344
const auto getAIXFuncEntryPointSymbolSDNode =
53395345
[&](StringRef FuncName, bool IsDeclaration,
53405346
const XCOFF::StorageClass &SC) {
5341-
auto &Context = DAG.getMachineFunction().getMMI().getContext();
5347+
MCSymbolXCOFF *S = getFunctionEntryPointSymbol(FuncName);
53425348

5343-
MCSymbolXCOFF *S = cast<MCSymbolXCOFF>(
5344-
Context.getOrCreateSymbol(Twine(".") + Twine(FuncName)));
5349+
auto &Context = DAG.getMachineFunction().getMMI().getContext();
53455350

53465351
if (IsDeclaration && !S->hasRepresentedCsectSet()) {
53475352
// On AIX, an undefined symbol needs to be associated with a
@@ -5376,22 +5381,21 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
53765381

53775382
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
53785383
const char *SymName = S->getSymbol();
5379-
if (!Subtarget.isAIXABI())
5380-
return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(),
5381-
UsePlt ? PPCII::MO_PLT : 0);
5382-
5383-
// If there exists a user-declared function whose name is the same as the
5384-
// ExternalSymbol's, then we pick up the user-declared version.
5385-
const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
5386-
if (const Function *F =
5387-
dyn_cast_or_null<Function>(Mod->getNamedValue(SymName))) {
5388-
const XCOFF::StorageClass SC =
5389-
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F);
5390-
return getAIXFuncEntryPointSymbolSDNode(F->getName(), F->isDeclaration(),
5391-
SC);
5384+
if (Subtarget.isAIXABI()) {
5385+
// If there exists a user-declared function whose name is the same as the
5386+
// ExternalSymbol's, then we pick up the user-declared version.
5387+
const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
5388+
if (const Function *F =
5389+
dyn_cast_or_null<Function>(Mod->getNamedValue(SymName))) {
5390+
const XCOFF::StorageClass SC =
5391+
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F);
5392+
return getAIXFuncEntryPointSymbolSDNode(F->getName(),
5393+
F->isDeclaration(), SC);
5394+
}
5395+
SymName = getFunctionEntryPointSymbol(SymName)->getName().data();
53925396
}
5393-
5394-
return getAIXFuncEntryPointSymbolSDNode(SymName, true, XCOFF::C_EXT);
5397+
return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(),
5398+
UsePlt ? PPCII::MO_PLT : 0);
53955399
}
53965400

53975401
// No transformation needed.

llvm/lib/Target/PowerPC/PPCInstrInfo.td

+4
Original file line numberDiff line numberDiff line change
@@ -3246,9 +3246,13 @@ def : Pat<(PPCcall (i32 texternalsym:$dst)),
32463246
// Calls for AIX only
32473247
def : Pat<(PPCcall (i32 mcsym:$dst)),
32483248
(BL mcsym:$dst)>;
3249+
32493250
def : Pat<(PPCcall_nop (i32 mcsym:$dst)),
32503251
(BL_NOP mcsym:$dst)>;
32513252

3253+
def : Pat<(PPCcall_nop (i32 texternalsym:$dst)),
3254+
(BL_NOP texternalsym:$dst)>;
3255+
32523256
def : Pat<(PPCtc_return (i32 tglobaladdr:$dst), imm:$imm),
32533257
(TCRETURNdi tglobaladdr:$dst, imm:$imm)>;
32543258

llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ entry:
8888
; 32BIT-DAG: $r3 = COPY %0
8989
; 32BIT-DAG: $r4 = COPY %1
9090
; 32BIT-DAG: $r5 = COPY %2
91-
; 32BIT-NEXT: BL_NOP <mcsymbol .memcpy>, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
91+
; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
9292
; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1
9393
; 32BIT: ADJCALLSTACKDOWN 312, 0, implicit-def dead $r1, implicit $r1
9494
; 32BIT-DAG: $r3 = COPY %{{[0-9]+}}
@@ -120,7 +120,7 @@ entry:
120120
; 64BIT-DAG: $x3 = COPY %0
121121
; 64BIT-DAG: $x4 = COPY %1
122122
; 64BIT-DAG: $x5 = COPY %2
123-
; 64BIT-NEXT: BL8_NOP <mcsymbol .memcpy>, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3
123+
; 64BIT-NEXT: BL8_NOP &.memcpy, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3
124124
; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1
125125
; 64BIT: ADJCALLSTACKDOWN 368, 0, implicit-def dead $r1, implicit $r1
126126
; 64BIT-DAG: $x3 = COPY %{{[0-9]+}}
@@ -187,7 +187,7 @@ entry:
187187
; 32BIT-DAG: $r3 = COPY %2
188188
; 32BIT-DAG: $r4 = COPY %1
189189
; 32BIT-DAG: $r5 = COPY %3
190-
; 32BIT-NEXT: BL_NOP <mcsymbol .memcpy>, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
190+
; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
191191
; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1
192192
; 32BIT: ADJCALLSTACKDOWN 92, 0, implicit-def dead $r1, implicit $r1
193193
; 32BIT-DAG: $r3 = COPY %{{[0-9]+}}
@@ -305,7 +305,7 @@ entry:
305305
; 32BIT-DAG: $r3 = COPY %3
306306
; 32BIT-DAG: $r4 = COPY %4
307307
; 32BIT-DAG: $r5 = COPY %5
308-
; 32BIT-NEXT: BL_NOP <mcsymbol .memcpy>, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
308+
; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3
309309
; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1
310310
; 32BIT: ADJCALLSTACKDOWN 316, 0, implicit-def dead $r1, implicit $r1
311311
; 32BIT-DAG: $r3 = COPY %{{[0-9]+}}
@@ -349,7 +349,7 @@ entry:
349349
; 64BIT-DAG: $x3 = COPY %2
350350
; 64BIT-DAG: $x4 = COPY %1
351351
; 64BIT-DAG: $x5 = COPY %3
352-
; 64BIT-NEXT: BL8_NOP <mcsymbol .memcpy>, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3
352+
; 64BIT-NEXT: BL8_NOP &.memcpy, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3
353353
; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1
354354
; 64BIT: ADJCALLSTACKDOWN 344, 0, implicit-def dead $r1, implicit $r1
355355
; 64BIT-DAG: $x3 = COPY %{{[0-9]+}}

llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ entry:
1414

1515
declare double @llvm.ceil.f64(double)
1616

17-
; 32BIT: BL_NOP <mcsymbol .ceil>
18-
; 64BIT: BL8_NOP <mcsymbol .ceil>
17+
; 32BIT: BL_NOP &.ceil
18+
; 64BIT: BL8_NOP &.ceil
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 -mattr=-altivec < %s | \
2+
; RUN: FileCheck %s
3+
4+
; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr4 -mattr=-altivec < %s | \
5+
; RUN: FileCheck %s
6+
7+
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \
8+
; RUN: -mattr=-altivec -filetype=obj -o %t.o < %s
9+
; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefix=CHECKSYM %s
10+
; RUN: llvm-objdump -r -d --symbol-description %t.o | FileCheck --check-prefix=CHECKRELOC %s
11+
12+
; RUN: not --crash llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc64-ibm-aix-xcoff \
13+
; RUN: -mattr=-altivec -filetype=obj -o %t.o 2>&1 < %s | \
14+
; RUN: FileCheck --check-prefix=XCOFF64 %s
15+
; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet.
16+
17+
%struct.S = type { i32, i32 }
18+
19+
@s = external global %struct.S, align 4
20+
21+
define void @bar() {
22+
entry:
23+
%0 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4
24+
%1 = trunc i32 %0 to i8
25+
%2 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4
26+
call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (%struct.S* @s to i8*), i8 %1, i32 %2, i1 false)
27+
ret void
28+
}
29+
30+
declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg)
31+
32+
; CHECK-LABEL: .bar:
33+
; CHECK-NEXT: # %bb.0: # %entry
34+
; CHECK-NEXT: mflr 0
35+
36+
; CHECK: bl .memset
37+
38+
; CHECK: .extern .memset
39+
40+
; CHECKSYM: Symbol {
41+
; CHECKSYM-NEXT: Index: 0
42+
; CHECKSYM-NEXT: Name: .memset
43+
; CHECKSYM-NEXT: Value (RelocatableAddress): 0x0
44+
; CHECKSYM-NEXT: Section: N_UNDEF
45+
; CHECKSYM-NEXT: Type: 0x0
46+
; CHECKSYM-NEXT: StorageClass: C_EXT (0x2)
47+
; CHECKSYM-NEXT: NumberOfAuxEntries: 1
48+
; CHECKSYM-NEXT: CSECT Auxiliary Entry {
49+
; CHECKSYM-NEXT: Index: 1
50+
; CHECKSYM-NEXT: SectionLen: 0
51+
; CHECKSYM-NEXT: ParameterHashIndex: 0x0
52+
; CHECKSYM-NEXT: TypeChkSectNum: 0x0
53+
; CHECKSYM-NEXT: SymbolAlignmentLog2: 0
54+
; CHECKSYM-NEXT: SymbolType: XTY_ER (0x0)
55+
; CHECKSYM-NEXT: StorageMappingClass: XMC_PR (0x0)
56+
; CHECKSYM-NEXT: StabInfoIndex: 0x0
57+
; CHECKSYM-NEXT: StabSectNum: 0x0
58+
; CHECKSYM-NEXT: }
59+
; CHECKSYM-NEXT: }
60+
61+
; CHECKRELOC: 00000000 (idx: 6) .bar:
62+
; CHECKRELOC-NEXT: 0: 7c 08 02 a6 mflr 0
63+
; CHECKRELOC-NEXT: 4: 90 01 00 08 stw 0, 8(1)
64+
; CHECKRELOC-NEXT: 8: 94 21 ff c0 stwu 1, -64(1)
65+
; CHECKRELOC-NEXT: c: 80 62 00 00 lwz 3, 0(2)
66+
; CHECKRELOC-NEXT: 0000000e: R_TOC (idx: 12) s[TC]
67+
; CHECKRELOC-NEXT: 10: 80 83 00 04 lwz 4, 4(3)
68+
; CHECKRELOC-NEXT: 14: 7c 85 23 78 mr 5, 4
69+
; CHECKRELOC-NEXT: 18: 4b ff ff e9 bl 0x0
70+
; CHECKRELOC-NEXT: 00000018: R_RBR (idx: 0) .memset[PR]

llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
; RUN: llvm-objdump -D %t.o | FileCheck --check-prefix=32-DIS %s
1010

11+
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \
12+
; RUN: -mcpu=pwr4 -mattr=-altivec < %s | \
13+
; RUN: FileCheck %s
14+
1115
; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \
1216
; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj < %s 2>&1 | FileCheck \
1317
; RUN: --check-prefix=64-CHECK %s
@@ -35,6 +39,8 @@ declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture r
3539
; 2. There is no relocation associated with the call, since callee is defined.
3640
; 3. Branch instruction in raw data is branching back to the right callee location.
3741

42+
; CHECK-NOT: .extern .memcpy
43+
3844
; 32-SYM: Symbol {{[{][[:space:]] *}}Index: [[#Index:]]{{[[:space:]] *}}Name: .memcpy
3945
; 32-SYM-NEXT: Value (RelocatableAddress): 0x0
4046
; 32-SYM-NEXT: Section: .text

0 commit comments

Comments
 (0)