Skip to content

Commit 319a89e

Browse files
committed
[AsmPrinter] Always emit global equivalents if there is non-global uses (llvm#145648)
A case found from rust-lang/rust#142752: https://llvm.godbolt.org/z/T7ce9saWh. We should emit `@bar_0` for the following code: ```llvm target triple = "x86_64-unknown-linux-gnu" @rel_0 = private unnamed_addr constant [1 x i32] [ i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_0 to i64), i64 ptrtoint (ptr @rel_0 to i64)) to i32)] @bar_0 = internal unnamed_addr constant ptr @foo_0, align 8 @foo_0 = external global ptr, align 8 define void @foo(ptr %arg0) { store ptr @bar_0, ptr %arg0, align 8 ret void } ``` (cherry picked from commit 630d55c)
1 parent ed65665 commit 319a89e

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,16 +2139,20 @@ void AsmPrinter::emitFunctionBody() {
21392139
}
21402140

21412141
/// Compute the number of Global Variables that uses a Constant.
2142-
static unsigned getNumGlobalVariableUses(const Constant *C) {
2143-
if (!C)
2142+
static unsigned getNumGlobalVariableUses(const Constant *C,
2143+
bool &HasNonGlobalUsers) {
2144+
if (!C) {
2145+
HasNonGlobalUsers = true;
21442146
return 0;
2147+
}
21452148

21462149
if (isa<GlobalVariable>(C))
21472150
return 1;
21482151

21492152
unsigned NumUses = 0;
21502153
for (const auto *CU : C->users())
2151-
NumUses += getNumGlobalVariableUses(dyn_cast<Constant>(CU));
2154+
NumUses +=
2155+
getNumGlobalVariableUses(dyn_cast<Constant>(CU), HasNonGlobalUsers);
21522156

21532157
return NumUses;
21542158
}
@@ -2159,7 +2163,8 @@ static unsigned getNumGlobalVariableUses(const Constant *C) {
21592163
/// candidates are skipped and are emitted later in case at least one cstexpr
21602164
/// isn't replaced by a PC relative GOT entry access.
21612165
static bool isGOTEquivalentCandidate(const GlobalVariable *GV,
2162-
unsigned &NumGOTEquivUsers) {
2166+
unsigned &NumGOTEquivUsers,
2167+
bool &HasNonGlobalUsers) {
21632168
// Global GOT equivalents are unnamed private globals with a constant
21642169
// pointer initializer to another global symbol. They must point to a
21652170
// GlobalVariable or Function, i.e., as GlobalValue.
@@ -2171,7 +2176,8 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV,
21712176
// To be a got equivalent, at least one of its users need to be a constant
21722177
// expression used by another global variable.
21732178
for (const auto *U : GV->users())
2174-
NumGOTEquivUsers += getNumGlobalVariableUses(dyn_cast<Constant>(U));
2179+
NumGOTEquivUsers +=
2180+
getNumGlobalVariableUses(dyn_cast<Constant>(U), HasNonGlobalUsers);
21752181

21762182
return NumGOTEquivUsers > 0;
21772183
}
@@ -2189,9 +2195,13 @@ void AsmPrinter::computeGlobalGOTEquivs(Module &M) {
21892195

21902196
for (const auto &G : M.globals()) {
21912197
unsigned NumGOTEquivUsers = 0;
2192-
if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers))
2198+
bool HasNonGlobalUsers = false;
2199+
if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers, HasNonGlobalUsers))
21932200
continue;
2194-
2201+
// If non-global variables use it, we still need to emit it.
2202+
// Add 1 here, then emit it in `emitGlobalGOTEquivs`.
2203+
if (HasNonGlobalUsers)
2204+
NumGOTEquivUsers += 1;
21952205
const MCSymbol *GOTEquivSym = getSymbol(&G);
21962206
GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers);
21972207
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
; RUN: llc < %s | FileCheck %s
2+
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
; Check that we emit the `@bar_*` symbols, and that we don't emit multiple symbols.
6+
7+
; CHECK-LABEL: .Lrel_0:
8+
; CHECK: .long foo_0@GOTPCREL+0
9+
; CHECK-LABEL: .Lrel_1_failed:
10+
; CHECK: .long bar_1-foo_0
11+
; CHECK-LABEL: .Lrel_2:
12+
; CHECK: .long foo_2@GOTPCREL+0
13+
14+
; CHECK: bar_0:
15+
; CHECK: bar_1:
16+
; CHECK: bar_2_indirect:
17+
18+
@rel_0 = private unnamed_addr constant [1 x i32] [
19+
i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_0 to i64), i64 ptrtoint (ptr @rel_0 to i64)) to i32)]
20+
@rel_1_failed = private unnamed_addr constant [1 x i32] [
21+
i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_1 to i64), i64 ptrtoint (ptr @foo_0 to i64)) to i32)]
22+
@rel_2 = private unnamed_addr constant [1 x i32] [
23+
i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_2_indirect to i64), i64 ptrtoint (ptr @rel_2 to i64)) to i32)]
24+
@bar_0 = internal unnamed_addr constant ptr @foo_0, align 8
25+
@bar_1 = internal unnamed_addr constant ptr @foo_1, align 8
26+
@bar_2_indirect = internal unnamed_addr constant ptr @foo_2, align 8
27+
@foo_0 = external global ptr, align 8
28+
@foo_1 = external global ptr, align 8
29+
@foo_2 = external global ptr, align 8
30+
31+
define void @foo(ptr %arg0, ptr %arg1) {
32+
store ptr @bar_0, ptr %arg0, align 8
33+
store ptr @bar_1, ptr %arg1, align 8
34+
store ptr getelementptr (i8, ptr @bar_2_indirect, i32 1), ptr %arg1, align 8
35+
ret void
36+
}

0 commit comments

Comments
 (0)