diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index e77abf429e6b4..c8f567e5f4195 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2139,16 +2139,20 @@ void AsmPrinter::emitFunctionBody() { } /// Compute the number of Global Variables that uses a Constant. -static unsigned getNumGlobalVariableUses(const Constant *C) { - if (!C) +static unsigned getNumGlobalVariableUses(const Constant *C, + bool &HasNonGlobalUsers) { + if (!C) { + HasNonGlobalUsers = true; return 0; + } if (isa(C)) return 1; unsigned NumUses = 0; for (const auto *CU : C->users()) - NumUses += getNumGlobalVariableUses(dyn_cast(CU)); + NumUses += + getNumGlobalVariableUses(dyn_cast(CU), HasNonGlobalUsers); return NumUses; } @@ -2159,7 +2163,8 @@ static unsigned getNumGlobalVariableUses(const Constant *C) { /// candidates are skipped and are emitted later in case at least one cstexpr /// isn't replaced by a PC relative GOT entry access. static bool isGOTEquivalentCandidate(const GlobalVariable *GV, - unsigned &NumGOTEquivUsers) { + unsigned &NumGOTEquivUsers, + bool &HasNonGlobalUsers) { // Global GOT equivalents are unnamed private globals with a constant // pointer initializer to another global symbol. They must point to a // GlobalVariable or Function, i.e., as GlobalValue. @@ -2171,7 +2176,8 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV, // To be a got equivalent, at least one of its users need to be a constant // expression used by another global variable. for (const auto *U : GV->users()) - NumGOTEquivUsers += getNumGlobalVariableUses(dyn_cast(U)); + NumGOTEquivUsers += + getNumGlobalVariableUses(dyn_cast(U), HasNonGlobalUsers); return NumGOTEquivUsers > 0; } @@ -2189,9 +2195,13 @@ void AsmPrinter::computeGlobalGOTEquivs(Module &M) { for (const auto &G : M.globals()) { unsigned NumGOTEquivUsers = 0; - if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers)) + bool HasNonGlobalUsers = false; + if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers, HasNonGlobalUsers)) continue; - + // If non-global variables use it, we still need to emit it. + // Add 1 here, then emit it in `emitGlobalGOTEquivs`. + if (HasNonGlobalUsers) + NumGOTEquivUsers += 1; const MCSymbol *GOTEquivSym = getSymbol(&G); GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers); } diff --git a/llvm/test/MC/X86/gotpcrel-non-globals.ll b/llvm/test/MC/X86/gotpcrel-non-globals.ll new file mode 100644 index 0000000000000..222d2d73ff728 --- /dev/null +++ b/llvm/test/MC/X86/gotpcrel-non-globals.ll @@ -0,0 +1,36 @@ +; RUN: llc < %s | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +; Check that we emit the `@bar_*` symbols, and that we don't emit multiple symbols. + +; CHECK-LABEL: .Lrel_0: +; CHECK: .long foo_0@GOTPCREL+0 +; CHECK-LABEL: .Lrel_1_failed: +; CHECK: .long bar_1-foo_0 +; CHECK-LABEL: .Lrel_2: +; CHECK: .long foo_2@GOTPCREL+0 + +; CHECK: bar_0: +; CHECK: bar_1: +; CHECK: bar_2_indirect: + +@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)] +@rel_1_failed = private unnamed_addr constant [1 x i32] [ + i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_1 to i64), i64 ptrtoint (ptr @foo_0 to i64)) to i32)] +@rel_2 = private unnamed_addr constant [1 x i32] [ + i32 trunc (i64 sub (i64 ptrtoint (ptr @bar_2_indirect to i64), i64 ptrtoint (ptr @rel_2 to i64)) to i32)] +@bar_0 = internal unnamed_addr constant ptr @foo_0, align 8 +@bar_1 = internal unnamed_addr constant ptr @foo_1, align 8 +@bar_2_indirect = internal unnamed_addr constant ptr @foo_2, align 8 +@foo_0 = external global ptr, align 8 +@foo_1 = external global ptr, align 8 +@foo_2 = external global ptr, align 8 + +define void @foo(ptr %arg0, ptr %arg1) { + store ptr @bar_0, ptr %arg0, align 8 + store ptr @bar_1, ptr %arg1, align 8 + store ptr getelementptr (i8, ptr @bar_2_indirect, i32 1), ptr %arg1, align 8 + ret void +}