Skip to content

Commit 630d55c

Browse files
authored
[AsmPrinter] Always emit global equivalents if there is non-global uses (#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 } ```
1 parent 892a263 commit 630d55c

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
@@ -2142,16 +2142,20 @@ void AsmPrinter::emitFunctionBody() {
21422142
}
21432143

21442144
/// Compute the number of Global Variables that uses a Constant.
2145-
static unsigned getNumGlobalVariableUses(const Constant *C) {
2146-
if (!C)
2145+
static unsigned getNumGlobalVariableUses(const Constant *C,
2146+
bool &HasNonGlobalUsers) {
2147+
if (!C) {
2148+
HasNonGlobalUsers = true;
21472149
return 0;
2150+
}
21482151

21492152
if (isa<GlobalVariable>(C))
21502153
return 1;
21512154

21522155
unsigned NumUses = 0;
21532156
for (const auto *CU : C->users())
2154-
NumUses += getNumGlobalVariableUses(dyn_cast<Constant>(CU));
2157+
NumUses +=
2158+
getNumGlobalVariableUses(dyn_cast<Constant>(CU), HasNonGlobalUsers);
21552159

21562160
return NumUses;
21572161
}
@@ -2162,7 +2166,8 @@ static unsigned getNumGlobalVariableUses(const Constant *C) {
21622166
/// candidates are skipped and are emitted later in case at least one cstexpr
21632167
/// isn't replaced by a PC relative GOT entry access.
21642168
static bool isGOTEquivalentCandidate(const GlobalVariable *GV,
2165-
unsigned &NumGOTEquivUsers) {
2169+
unsigned &NumGOTEquivUsers,
2170+
bool &HasNonGlobalUsers) {
21662171
// Global GOT equivalents are unnamed private globals with a constant
21672172
// pointer initializer to another global symbol. They must point to a
21682173
// GlobalVariable or Function, i.e., as GlobalValue.
@@ -2174,7 +2179,8 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV,
21742179
// To be a got equivalent, at least one of its users need to be a constant
21752180
// expression used by another global variable.
21762181
for (const auto *U : GV->users())
2177-
NumGOTEquivUsers += getNumGlobalVariableUses(dyn_cast<Constant>(U));
2182+
NumGOTEquivUsers +=
2183+
getNumGlobalVariableUses(dyn_cast<Constant>(U), HasNonGlobalUsers);
21782184

21792185
return NumGOTEquivUsers > 0;
21802186
}
@@ -2192,9 +2198,13 @@ void AsmPrinter::computeGlobalGOTEquivs(Module &M) {
21922198

21932199
for (const auto &G : M.globals()) {
21942200
unsigned NumGOTEquivUsers = 0;
2195-
if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers))
2201+
bool HasNonGlobalUsers = false;
2202+
if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers, HasNonGlobalUsers))
21962203
continue;
2197-
2204+
// If non-global variables use it, we still need to emit it.
2205+
// Add 1 here, then emit it in `emitGlobalGOTEquivs`.
2206+
if (HasNonGlobalUsers)
2207+
NumGOTEquivUsers += 1;
21982208
const MCSymbol *GOTEquivSym = getSymbol(&G);
21992209
GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers);
22002210
}
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)