[llvm] [AsmPrinter] Always emit global equivalents if there is non-global uses (PR #145648)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 25 02:13:32 PDT 2025


https://github.com/dianqk updated https://github.com/llvm/llvm-project/pull/145648

>From 1e606e0c9fdb83ee5447d83b85c5b44f43f13b9a Mon Sep 17 00:00:00 2001
From: dianqk <dianqk at dianqk.net>
Date: Wed, 25 Jun 2025 14:09:00 +0800
Subject: [PATCH 1/4] [AsmPrinter] Always emit global equivalents if there are
 non-global uses

---
 llvm/include/llvm/CodeGen/AsmPrinter.h     |  8 +++-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 46 ++++++++++++++--------
 llvm/test/MC/X86/gotpcrel-non-globals.ll   | 28 +++++++++++++
 3 files changed, 63 insertions(+), 19 deletions(-)
 create mode 100644 llvm/test/MC/X86/gotpcrel-non-globals.ll

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 6ad54fcd6d0e5..22764409d0c54 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -151,8 +151,12 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
 
   /// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
   /// its number of uses by other globals.
-  using GOTEquivUsePair = std::pair<const GlobalVariable *, unsigned>;
-  MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
+  struct GOTEquivUse {
+    const GlobalVariable *GV;
+    unsigned NumUses;
+    bool HasNonGlobalUsers;
+  };
+  MapVector<const MCSymbol *, GOTEquivUse> GlobalGOTEquivs;
 
   // Flags representing which CFI section is required for a function/module.
   enum class CFISection : unsigned {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 3b96225236cd6..4ee05423aa96d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -740,9 +740,11 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
     if (emitSpecialLLVMGlobal(GV))
       return;
 
-    // Skip the emission of global equivalents. The symbol can be emitted later
-    // on by emitGlobalGOTEquivs in case it turns out to be needed.
-    if (GlobalGOTEquivs.count(getSymbol(GV)))
+    // Skip the emission of global equivalents if they are only used by global
+    // values. The symbol can be emitted later on by emitGlobalGOTEquivs in case
+    // it turns out to be needed.
+    if (GlobalGOTEquivs.contains(getSymbol(GV)) &&
+        !GlobalGOTEquivs[getSymbol(GV)].HasNonGlobalUsers)
       return;
 
     if (isVerbose()) {
@@ -2142,16 +2144,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<GlobalVariable>(C))
     return 1;
 
   unsigned NumUses = 0;
   for (const auto *CU : C->users())
-    NumUses += getNumGlobalVariableUses(dyn_cast<Constant>(CU));
+    NumUses +=
+        getNumGlobalVariableUses(dyn_cast<Constant>(CU), HasNonGlobalUsers);
 
   return NumUses;
 }
@@ -2162,7 +2168,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.
@@ -2174,7 +2181,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<Constant>(U));
+    NumGOTEquivUsers +=
+        getNumGlobalVariableUses(dyn_cast<Constant>(U), HasNonGlobalUsers);
 
   return NumGOTEquivUsers > 0;
 }
@@ -2192,11 +2200,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;
 
     const MCSymbol *GOTEquivSym = getSymbol(&G);
-    GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers);
+    GlobalGOTEquivs[GOTEquivSym] =
+        AsmPrinter::GOTEquivUse{&G, NumGOTEquivUsers, HasNonGlobalUsers};
   }
 }
 
@@ -2209,9 +2219,9 @@ void AsmPrinter::emitGlobalGOTEquivs() {
 
   SmallVector<const GlobalVariable *, 8> FailedCandidates;
   for (auto &I : GlobalGOTEquivs) {
-    const GlobalVariable *GV = I.second.first;
-    unsigned Cnt = I.second.second;
-    if (Cnt)
+    const GlobalVariable *GV = I.second.GV;
+    unsigned Cnt = I.second.NumUses;
+    if (Cnt > 0 && !I.second.HasNonGlobalUsers)
       FailedCandidates.push_back(GV);
   }
   GlobalGOTEquivs.clear();
@@ -3992,9 +4002,10 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   //    .long 42
   //  foo:
   //    .long bar at GOTPCREL+<gotpcrelcst>
-  AsmPrinter::GOTEquivUsePair Result = AP.GlobalGOTEquivs[GOTEquivSym];
-  const GlobalVariable *GV = Result.first;
-  int NumUses = (int)Result.second;
+  AsmPrinter::GOTEquivUse Result = AP.GlobalGOTEquivs[GOTEquivSym];
+  const GlobalVariable *GV = Result.GV;
+  bool HasNonGlobalUsers = Result.HasNonGlobalUsers;
+  int NumUses = (int)Result.NumUses;
   const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0));
   const MCSymbol *FinalSym = AP.getSymbol(FinalGV);
   *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(
@@ -4003,7 +4014,8 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   // Update GOT equivalent usage information
   --NumUses;
   if (NumUses >= 0)
-    AP.GlobalGOTEquivs[GOTEquivSym] = std::make_pair(GV, NumUses);
+    AP.GlobalGOTEquivs[GOTEquivSym] =
+        AsmPrinter::GOTEquivUse{GV, (unsigned)NumUses, HasNonGlobalUsers};
 }
 
 static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,
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..cbf22cd1e4ac0
--- /dev/null
+++ b/llvm/test/MC/X86/gotpcrel-non-globals.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+; Check that we submit the `@bar_*` symbols, and that we don't submit multiple symbols.
+
+; CHECK-LABEL: .Lrel_0:
+; CHECK: .long   foo_0 at GOTPCREL+0
+; CHECK-LABEL: .Lrel_1_failed:
+; CHECK: .long   bar_1-foo_0
+
+; CHECK: bar_0:
+; CHECK: bar_1:
+
+ at 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)]
+ at 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)]
+ at bar_0 = internal unnamed_addr constant ptr @foo_0, align 8
+ at bar_1 = internal unnamed_addr constant ptr @foo_1, align 8
+ at foo_0 = external global ptr, align 8
+ at foo_1 = 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
+  ret void
+}

>From f94a0e3e1b0617a075a5750eb15dbd8fc137323c Mon Sep 17 00:00:00 2001
From: dianqk <dianqk at dianqk.net>
Date: Wed, 25 Jun 2025 16:20:53 +0800
Subject: [PATCH 2/4] emit global variables by adding 1

---
 llvm/include/llvm/CodeGen/AsmPrinter.h     |  8 ++----
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 32 ++++++++++------------
 2 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 22764409d0c54..6ad54fcd6d0e5 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -151,12 +151,8 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
 
   /// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
   /// its number of uses by other globals.
-  struct GOTEquivUse {
-    const GlobalVariable *GV;
-    unsigned NumUses;
-    bool HasNonGlobalUsers;
-  };
-  MapVector<const MCSymbol *, GOTEquivUse> GlobalGOTEquivs;
+  using GOTEquivUsePair = std::pair<const GlobalVariable *, unsigned>;
+  MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
 
   // Flags representing which CFI section is required for a function/module.
   enum class CFISection : unsigned {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 4ee05423aa96d..754dba73673c2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -740,11 +740,9 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
     if (emitSpecialLLVMGlobal(GV))
       return;
 
-    // Skip the emission of global equivalents if they are only used by global
-    // values. The symbol can be emitted later on by emitGlobalGOTEquivs in case
-    // it turns out to be needed.
-    if (GlobalGOTEquivs.contains(getSymbol(GV)) &&
-        !GlobalGOTEquivs[getSymbol(GV)].HasNonGlobalUsers)
+    // Skip the emission of global equivalents. The symbol can be emitted later
+    // on by emitGlobalGOTEquivs in case it turns out to be needed.
+    if (GlobalGOTEquivs.count(getSymbol(GV)))
       return;
 
     if (isVerbose()) {
@@ -2203,10 +2201,12 @@ void AsmPrinter::computeGlobalGOTEquivs(Module &M) {
     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] =
-        AsmPrinter::GOTEquivUse{&G, NumGOTEquivUsers, HasNonGlobalUsers};
+    GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers);
   }
 }
 
@@ -2219,9 +2219,9 @@ void AsmPrinter::emitGlobalGOTEquivs() {
 
   SmallVector<const GlobalVariable *, 8> FailedCandidates;
   for (auto &I : GlobalGOTEquivs) {
-    const GlobalVariable *GV = I.second.GV;
-    unsigned Cnt = I.second.NumUses;
-    if (Cnt > 0 && !I.second.HasNonGlobalUsers)
+    const GlobalVariable *GV = I.second.first;
+    unsigned Cnt = I.second.second;
+    if (Cnt)
       FailedCandidates.push_back(GV);
   }
   GlobalGOTEquivs.clear();
@@ -4002,10 +4002,9 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   //    .long 42
   //  foo:
   //    .long bar at GOTPCREL+<gotpcrelcst>
-  AsmPrinter::GOTEquivUse Result = AP.GlobalGOTEquivs[GOTEquivSym];
-  const GlobalVariable *GV = Result.GV;
-  bool HasNonGlobalUsers = Result.HasNonGlobalUsers;
-  int NumUses = (int)Result.NumUses;
+  AsmPrinter::GOTEquivUsePair Result = AP.GlobalGOTEquivs[GOTEquivSym];
+  const GlobalVariable *GV = Result.first;
+  int NumUses = (int)Result.second;
   const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0));
   const MCSymbol *FinalSym = AP.getSymbol(FinalGV);
   *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(
@@ -4014,8 +4013,7 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   // Update GOT equivalent usage information
   --NumUses;
   if (NumUses >= 0)
-    AP.GlobalGOTEquivs[GOTEquivSym] =
-        AsmPrinter::GOTEquivUse{GV, (unsigned)NumUses, HasNonGlobalUsers};
+    AP.GlobalGOTEquivs[GOTEquivSym] = std::make_pair(GV, NumUses);
 }
 
 static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,

>From cd85ee4d3e4260ff1d26c026c30c355df377abbb Mon Sep 17 00:00:00 2001
From: dianqk <dianqk at dianqk.net>
Date: Wed, 25 Jun 2025 17:06:52 +0800
Subject: [PATCH 3/4] add a test case for an indirect use

---
 llvm/test/MC/X86/gotpcrel-non-globals.ll | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/test/MC/X86/gotpcrel-non-globals.ll b/llvm/test/MC/X86/gotpcrel-non-globals.ll
index cbf22cd1e4ac0..c3d43d6f8e332 100644
--- a/llvm/test/MC/X86/gotpcrel-non-globals.ll
+++ b/llvm/test/MC/X86/gotpcrel-non-globals.ll
@@ -8,21 +8,29 @@ target triple = "x86_64-unknown-linux-gnu"
 ; CHECK: .long   foo_0 at GOTPCREL+0
 ; CHECK-LABEL: .Lrel_1_failed:
 ; CHECK: .long   bar_1-foo_0
+; CHECK-LABEL: .Lrel_2:
+; CHECK: .long   foo_2 at 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)]
+ at 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
+ at 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
+ at 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
 }

>From edd82b5c8c995903b7b80f09c0c36eab3e0a81a7 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk at dianqk.net>
Date: Wed, 25 Jun 2025 17:13:17 +0800
Subject: [PATCH 4/4] typo

---
 llvm/test/MC/X86/gotpcrel-non-globals.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/MC/X86/gotpcrel-non-globals.ll b/llvm/test/MC/X86/gotpcrel-non-globals.ll
index c3d43d6f8e332..222d2d73ff728 100644
--- a/llvm/test/MC/X86/gotpcrel-non-globals.ll
+++ b/llvm/test/MC/X86/gotpcrel-non-globals.ll
@@ -2,7 +2,7 @@
 
 target triple = "x86_64-unknown-linux-gnu"
 
-; Check that we submit the `@bar_*` symbols, and that we don't submit multiple symbols.
+; Check that we emit the `@bar_*` symbols, and that we don't emit multiple symbols.
 
 ; CHECK-LABEL: .Lrel_0:
 ; CHECK: .long   foo_0 at GOTPCREL+0



More information about the llvm-commits mailing list