Skip to content

Commit b98b170

Browse files
committed
[XCOFF] Enable symbol alias for AIX
Summary: AIX assembly's .set directive is not usable for aliasing purpose. We need to use extra-label-at-defintion strategy to generate symbol aliasing on AIX. Reviewed By: DiggerLin, Xiangling_L Differential Revision: https://reviews.llvm.org/D83252
1 parent 2a6c871 commit b98b170

File tree

8 files changed

+199
-32
lines changed

8 files changed

+199
-32
lines changed

llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
246246
const Constant *C,
247247
Align &Alignment) const override;
248248

249-
static XCOFF::StorageClass getStorageClassForGlobal(const GlobalObject *GO);
249+
static XCOFF::StorageClass getStorageClassForGlobal(const GlobalValue *GV);
250250

251251
MCSection *
252252
getSectionForFunctionDescriptor(const Function *F,
@@ -263,7 +263,7 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
263263
MCSymbol *getTargetSymbol(const GlobalValue *GV,
264264
const TargetMachine &TM) const override;
265265

266-
MCSymbol *getFunctionEntryPointSymbol(const Function *F,
266+
MCSymbol *getFunctionEntryPointSymbol(const GlobalValue *Func,
267267
const TargetMachine &TM) const override;
268268
};
269269

llvm/include/llvm/Target/TargetLoweringObjectFile.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
247247

248248
/// If supported, return the function entry point symbol.
249249
/// Otherwise, returns nulltpr.
250-
virtual MCSymbol *getFunctionEntryPointSymbol(const Function *F,
250+
/// Func must be a function or an alias which has a function as base object.
251+
virtual MCSymbol *getFunctionEntryPointSymbol(const GlobalValue *Func,
251252
const TargetMachine &TM) const {
252253
return nullptr;
253254
}

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,16 +1390,7 @@ void AsmPrinter::emitGlobalGOTEquivs() {
13901390
void AsmPrinter::emitGlobalIndirectSymbol(Module &M,
13911391
const GlobalIndirectSymbol& GIS) {
13921392
MCSymbol *Name = getSymbol(&GIS);
1393-
1394-
if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective())
1395-
OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
1396-
else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage())
1397-
OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
1398-
else
1399-
assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage");
1400-
14011393
bool IsFunction = GIS.getValueType()->isFunctionTy();
1402-
14031394
// Treat bitcasts of functions as functions also. This is important at least
14041395
// on WebAssembly where object and function addresses can't alias each other.
14051396
if (!IsFunction)
@@ -1408,6 +1399,30 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M,
14081399
IsFunction =
14091400
CE->getOperand(0)->getType()->getPointerElementType()->isFunctionTy();
14101401

1402+
// AIX's assembly directive `.set` is not usable for aliasing purpose,
1403+
// so AIX has to use the extra-label-at-definition strategy. At this
1404+
// point, all the extra label is emitted, we just have to emit linkage for
1405+
// those labels.
1406+
if (TM.getTargetTriple().isOSBinFormatXCOFF()) {
1407+
assert(!isa<GlobalIFunc>(GIS) && "IFunc is not supported on AIX.");
1408+
assert(MAI->hasVisibilityOnlyWithLinkage() &&
1409+
"Visibility should be handled with emitLinkage() on AIX.");
1410+
emitLinkage(&GIS, Name);
1411+
// If it's a function, also emit linkage for aliases of function entry
1412+
// point.
1413+
if (IsFunction)
1414+
emitLinkage(&GIS,
1415+
getObjFileLowering().getFunctionEntryPointSymbol(&GIS, TM));
1416+
return;
1417+
}
1418+
1419+
if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective())
1420+
OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
1421+
else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage())
1422+
OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
1423+
else
1424+
assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage");
1425+
14111426
// Set the symbol type to function if the alias has a function type.
14121427
// This affects codegen when the aliasee is not a function.
14131428
if (IsFunction)

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,9 +2125,11 @@ const MCExpr *TargetLoweringObjectFileXCOFF::lowerRelativeReference(
21252125
report_fatal_error("XCOFF not yet implemented.");
21262126
}
21272127

2128-
XCOFF::StorageClass TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(
2129-
const GlobalObject *GO) {
2130-
switch (GO->getLinkage()) {
2128+
XCOFF::StorageClass
2129+
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(const GlobalValue *GV) {
2130+
assert(!isa<GlobalIFunc>(GV) && "GlobalIFunc is not supported on AIX.");
2131+
2132+
switch (GV->getLinkage()) {
21312133
case GlobalValue::InternalLinkage:
21322134
case GlobalValue::PrivateLinkage:
21332135
return XCOFF::C_HIDEXT;
@@ -2149,10 +2151,16 @@ XCOFF::StorageClass TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(
21492151
}
21502152

21512153
MCSymbol *TargetLoweringObjectFileXCOFF::getFunctionEntryPointSymbol(
2152-
const Function *F, const TargetMachine &TM) const {
2154+
const GlobalValue *Func, const TargetMachine &TM) const {
2155+
assert(
2156+
isa<Function>(Func) ||
2157+
(isa<GlobalAlias>(Func) &&
2158+
isa_and_nonnull<Function>(cast<GlobalAlias>(Func)->getBaseObject())) &&
2159+
"Func must be a function or an alias which has a function as base "
2160+
"object.");
21532161
SmallString<128> NameStr;
21542162
NameStr.push_back('.');
2155-
getNameWithPrefix(NameStr, F, TM);
2163+
getNameWithPrefix(NameStr, Func, TM);
21562164
return getContext().getOrCreateSymbol(NameStr);
21572165
}
21582166

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
154154
SmallPtrSet<MCSymbol *, 8> ExtSymSDNodeSymbols;
155155

156156
static void ValidateGV(const GlobalVariable *GV);
157+
// Record a list of GlobalAlias associated with a GlobalObject.
158+
// This is used for AIX's extra-label-at-definition aliasing strategy.
159+
DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>>
160+
GOAliasMap;
157161

158162
public:
159163
PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
@@ -173,6 +177,8 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
173177

174178
void emitFunctionDescriptor() override;
175179

180+
void emitFunctionEntryLabel() override;
181+
176182
void emitEndOfAsmFile(Module &) override;
177183

178184
void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override;
@@ -1729,6 +1735,10 @@ void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
17291735
emitLinkage(GV, EmittedInitSym);
17301736
emitAlignment(getGVAlignment(GV, DL), GV);
17311737
OutStreamer->emitLabel(EmittedInitSym);
1738+
// Emit aliasing label for global variable.
1739+
llvm::for_each(GOAliasMap[GV], [this](const GlobalAlias *Alias) {
1740+
OutStreamer->emitLabel(getSymbol(Alias));
1741+
});
17321742
emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer());
17331743
}
17341744

@@ -1740,6 +1750,13 @@ void PPCAIXAsmPrinter::emitFunctionDescriptor() {
17401750
// Emit function descriptor.
17411751
OutStreamer->SwitchSection(
17421752
cast<MCSymbolXCOFF>(CurrentFnDescSym)->getRepresentedCsect());
1753+
1754+
// Emit aliasing label for function descriptor csect.
1755+
llvm::for_each(GOAliasMap[&MF->getFunction()],
1756+
[this](const GlobalAlias *Alias) {
1757+
OutStreamer->emitLabel(getSymbol(Alias));
1758+
});
1759+
17431760
// Emit function entry point address.
17441761
OutStreamer->emitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext),
17451762
PointerSize);
@@ -1755,6 +1772,16 @@ void PPCAIXAsmPrinter::emitFunctionDescriptor() {
17551772
OutStreamer->SwitchSection(Current.first, Current.second);
17561773
}
17571774

1775+
void PPCAIXAsmPrinter::emitFunctionEntryLabel() {
1776+
PPCAsmPrinter::emitFunctionEntryLabel();
1777+
// Emit aliasing label for function entry point label.
1778+
llvm::for_each(
1779+
GOAliasMap[&MF->getFunction()], [this](const GlobalAlias *Alias) {
1780+
OutStreamer->emitLabel(
1781+
getObjFileLowering().getFunctionEntryPointSymbol(Alias, TM));
1782+
});
1783+
}
1784+
17581785
void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
17591786
// If there are no functions in this module, we will never need to reference
17601787
// the TOC base.
@@ -1790,10 +1817,6 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
17901817
}
17911818

17921819
bool PPCAIXAsmPrinter::doInitialization(Module &M) {
1793-
if (M.alias_size() > 0u)
1794-
report_fatal_error(
1795-
"module has aliases, which LLVM does not yet support for AIX");
1796-
17971820
const bool Result = PPCAsmPrinter::doInitialization(M);
17981821

17991822
auto setCsectAlignment = [this](const GlobalObject *GO) {
@@ -1819,6 +1842,15 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
18191842
for (const auto &F : M)
18201843
setCsectAlignment(&F);
18211844

1845+
// Construct an aliasing list for each GlobalObject.
1846+
for (const auto &Alias : M.aliases()) {
1847+
const GlobalObject *Base = Alias.getBaseObject();
1848+
if (!Base)
1849+
report_fatal_error(
1850+
"alias without a base object is not yet supported on AIX");
1851+
GOAliasMap[Base].push_back(&Alias);
1852+
}
1853+
18221854
return Result;
18231855
}
18241856

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5372,10 +5372,9 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG,
53725372
UsePlt ? PPCII::MO_PLT : 0);
53735373

53745374
assert(!isa<GlobalIFunc>(GV) && "IFunc is not supported on AIX.");
5375-
const GlobalObject *GO = cast<GlobalObject>(GV);
53765375
const XCOFF::StorageClass SC =
5377-
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
5378-
return getAIXFuncEntryPointSymbolSDNode(GO->getName(), GO->isDeclaration(),
5376+
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV);
5377+
return getAIXFuncEntryPointSymbolSDNode(GV->getName(), GV->isDeclaration(),
53795378
SC);
53805379
}
53815380

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
; RUN: not --crash llc < %s -mtriple powerpc-ibm-aix-xcoff 2>&1 | FileCheck %s
2+
; RUN: not --crash llc < %s -mtriple powerpc64-ibm-aix-xcoff 2>&1 | FileCheck %s
3+
; CHECK: ERROR: alias without a base object is not yet supported on AIX
4+
5+
@bar = global i32 42
6+
@test = alias i32, inttoptr(i32 42 to i32*)
Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,116 @@
1-
; RUN: not --crash llc < %s -mtriple powerpc-ibm-aix-xcoff 2>&1 | FileCheck %s
2-
; RUN: not --crash llc < %s -mtriple powerpc64-ibm-aix-xcoff 2>&1 | FileCheck %s
1+
; TODO: Add object generation test when visibility for object generation
2+
; is implemnted.
33

4-
; Check that, while generation of aliases on AIX remains unimplemented, llc dies
5-
; with an appropriate message instead of generating incorrect output when an
6-
; alias is encountered.
4+
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \
5+
; RUN: -mattr=-altivec < %s | \
6+
; RUN: FileCheck --check-prefix=ASM %s
7+
; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr4 \
8+
; RUN: -mattr=-altivec < %s | \
9+
; RUN: FileCheck --check-prefix=ASM %s
710

8-
define i32 @a() { ret i32 0 }
9-
; CHECK: ERROR: module has aliases
10-
@b = internal alias i32 (), i32 ()* @a
11+
@var = global i32 42
12+
@var1 = alias i32, i32* @var
13+
@var2 = alias i32, i32* @var1
14+
@var_l = linkonce_odr alias i32, i32* @var
15+
@var_i = internal alias i32, i32* @var
16+
@var_h = hidden alias i32, i32* @var
17+
@var_p = protected alias i32, i32* @var
18+
19+
@array = global [2 x i32] [i32 1, i32 2], align 4
20+
@x = global i32* bitcast (i8* getelementptr (i8, i8* bitcast ([2 x i32]* @array to i8*), i64 4) to i32*), align 4
21+
@bitcast_alias = alias i32*, i32** @x
22+
23+
define i32 @fun() {
24+
ret i32 0
25+
}
26+
27+
%FunTy = type i32()
28+
@fun_weak = weak alias %FunTy, %FunTy* @fun
29+
@fun_hidden = hidden alias %FunTy, %FunTy* @fun
30+
@fun_ptr = global i32()* @fun_weak
31+
32+
define i32 @test() {
33+
entry:
34+
%tmp = load i32, i32* @var1
35+
%tmp1 = load i32, i32* @var2
36+
%tmp0 = load i32, i32* @var_i
37+
%tmp2 = call i32 @fun()
38+
%tmp3 = add i32 %tmp, %tmp2
39+
%tmp4 = call i32 @fun_weak()
40+
%tmp5 = add i32 %tmp3, %tmp4
41+
%tmp6 = add i32 %tmp1, %tmp5
42+
%tmp7 = add i32 %tmp6, %tmp0
43+
%fun_ptr1 = alloca i32 ()*
44+
store i32 ()* @fun_weak, i32 ()** %fun_ptr1
45+
%callee.knr.cast = bitcast i32 ()** %fun_ptr1 to i32 ()*
46+
%tmp8 = call i32 %callee.knr.cast()
47+
%tmp9 = call i32 @fun_hidden()
48+
%tmp10 = add i32 %tmp7, %tmp8
49+
%tmp11 = add i32 %tmp10, %tmp9
50+
ret i32 %tmp11
51+
}
52+
53+
; ASM: .globl fun[DS]
54+
; ASM-NEXT: .globl .fun
55+
; ASM-NEXT: .align 4
56+
; ASM-NEXT: .csect fun[DS]
57+
; ASM-NEXT: fun_weak: # @fun
58+
; ASM-NEXT: fun_hidden:
59+
; ASM: .csect .text[PR],2
60+
; ASM-NEXT: .fun:
61+
; ASM-NEXT: .fun_weak:
62+
; ASM-NEXT: .fun_hidden:
63+
; ASM-NEXT: # %bb.0:
64+
; ASM-NEXT: li 3, 0
65+
; ASM-NEXT: blr
66+
; ASM-NEXT: # -- End function
67+
; ASM: .csect .text[PR],2
68+
; ASM-NEXT: .test:
69+
; ASM-NEXT: # %bb.0: # %entry
70+
; ASM: bl .fun
71+
; ASM-NEXT: nop
72+
; ASM: bl .fun_weak
73+
; ASM-NEXT: nop
74+
; ASM: bl .fun_hidden
75+
; ASM: # -- End function
76+
; ASM-NEXT: .csect .data[RW]
77+
; ASM-NEXT: .globl var
78+
; ASM: var:
79+
; ASM-NEXT: var1:
80+
; ASM-NEXT: var2:
81+
; ASM-NEXT: var_l:
82+
; ASM-NEXT: var_i:
83+
; ASM-NEXT: var_h:
84+
; ASM-NEXT: var_p:
85+
; ASM-NEXT: .vbyte 4, 42
86+
; ASM-NEXT: .globl array
87+
; ASM: array:
88+
; ASM-NEXT: .vbyte 4, 1 # 0x1
89+
; ASM-NEXT: .vbyte 4, 2 # 0x2
90+
; ASM-NEXT: .globl x
91+
; ASM: x:
92+
; ASM-NEXT: bitcast_alias:
93+
; ASM-NEXT: .vbyte {{[0-9]+}}, array+4
94+
; ASM-NEXT: .globl fun_ptr
95+
; ASM: fun_ptr:
96+
; ASM-NEXT: .vbyte {{[0-9]+}}, fun_weak
97+
; ASM-NEXT: .globl var1
98+
; ASM-NEXT: .globl var2
99+
; ASM-NEXT: .weak var_l
100+
; ASM-NEXT: .lglobl var_i
101+
; ASM-NEXT: .globl var_h,hidden
102+
; ASM-NEXT: .globl var_p,protected
103+
; ASM-NEXT: .globl bitcast_alias
104+
; ASM-NEXT: .weak fun_weak
105+
; ASM-NEXT: .weak .fun_weak
106+
; ASM-NEXT: .globl fun_hidden,hidden
107+
; ASM-NEXT: .globl .fun_hidden,hidden
108+
; ASM-NEXT: .toc
109+
; ASM-NEXT: L..C0:
110+
; ASM-NEXT: .tc var1[TC],var1
111+
; ASM-NEXT: L..C1:
112+
; ASM-NEXT: .tc var2[TC],var2
113+
; ASM-NEXT: L..C2:
114+
; ASM-NEXT: .tc var_i[TC],var_i
115+
; ASM-NEXT: L..C3:
116+
; ASM-NEXT: .tc fun_weak[TC],fun_weak

0 commit comments

Comments
 (0)