[llvm] [NVPTX] Trim trailing zeros from aggregate initializers with symbols (PR #226960)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 28 04:20:37 PDT 2026


https://github.com/wenhu1024 created https://github.com/llvm/llvm-project/pull/226960

Hi @AlexMaclean, would you mind reviewing this PR?

This follows up on the TODO introduced in #79062 and extends incomplete
aggregate initializers to aggregates containing symbols. It covers both
byte/mask and aligned word emission, with tests for 32-bit and 64-bit targets.

Thanks!

>From 5e9cd3580e3c5802a9ab670bbae11ca8bf26a7fa Mon Sep 17 00:00:00 2001
From: wenhu1024 <1340773297 at qq.com>
Date: Mon, 28 Sep 2026 19:14:41 +0800
Subject: [PATCH] [NVPTX] Trim trailing zeros from aggregate initializers with
 symbols

---
 llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp     | 33 +++++++++++++------
 .../CodeGen/NVPTX/global-incomplete-init.ll   |  2 +-
 llvm/test/CodeGen/NVPTX/packed-aggr.ll        | 21 +++++++++---
 3 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
index a7d7b55c81fff..82dc0d99da927 100644
--- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
@@ -208,6 +208,7 @@ class NVPTXAsmPrinter : public AsmPrinter {
     void printWords(raw_ostream &os);
 
   private:
+    unsigned getInitializerSize(unsigned PtrSize) const;
     void printSymbol(unsigned nSym, raw_ostream &os);
   };
 
@@ -1690,18 +1691,28 @@ void NVPTXAsmPrinter::AggBuffer::printSymbol(unsigned nSym, raw_ostream &os) {
     llvm_unreachable("symbol type unknown");
 }
 
-void NVPTXAsmPrinter::AggBuffer::printBytes(raw_ostream &os) {
-  unsigned int ptrSize = AP.MAI.getCodePointerSize();
+unsigned NVPTXAsmPrinter::AggBuffer::getInitializerSize(unsigned PtrSize) const {
   // Do not emit trailing zero initializers. They will be zero-initialized by
   // ptxas. This saves on both space requirements for the generated PTX and on
   // memory use by ptxas. (See:
   // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#global-state-space)
-  unsigned int InitializerCount = Size;
-  // TODO: symbols make this harder, but it would still be good to trim trailing
-  // 0s for aggs with symbols as well.
-  if (numSymbols() == 0)
-    while (InitializerCount >= 1 && !buffer[InitializerCount - 1])
-      InitializerCount--;
+  //
+  // Symbols are represented by zero-filled placeholders in the buffer, so do
+  // not trim into the final symbol even if it is followed only by zeros.
+  unsigned MinimumSize = symbolPosInBuffer.empty()
+                             ? 0
+                             : symbolPosInBuffer.back() + PtrSize;
+  assert(MinimumSize <= Size);
+
+  unsigned InitializerSize = Size;
+  while (InitializerSize > MinimumSize && !buffer[InitializerSize - 1])
+    --InitializerSize;
+  return InitializerSize;
+}
+
+void NVPTXAsmPrinter::AggBuffer::printBytes(raw_ostream &os) {
+  unsigned int ptrSize = AP.MAI.getCodePointerSize();
+  unsigned int InitializerCount = getInitializerSize(ptrSize);
 
   symbolPosInBuffer.push_back(InitializerCount);
   unsigned int nSym = 0;
@@ -1734,11 +1745,13 @@ void NVPTXAsmPrinter::AggBuffer::printBytes(raw_ostream &os) {
 
 void NVPTXAsmPrinter::AggBuffer::printWords(raw_ostream &os) {
   unsigned int ptrSize = AP.MAI.getCodePointerSize();
-  symbolPosInBuffer.push_back(Size);
+  unsigned int InitializerSize =
+      alignTo(getInitializerSize(ptrSize), ptrSize);
+  symbolPosInBuffer.push_back(InitializerSize);
   unsigned int nSym = 0;
   unsigned int nextSymbolPos = symbolPosInBuffer[nSym];
   assert(nextSymbolPos % ptrSize == 0);
-  for (unsigned int pos = 0; pos < Size; pos += ptrSize) {
+  for (unsigned int pos = 0; pos < InitializerSize; pos += ptrSize) {
     if (pos)
       os << ", ";
     if (pos == nextSymbolPos) {
diff --git a/llvm/test/CodeGen/NVPTX/global-incomplete-init.ll b/llvm/test/CodeGen/NVPTX/global-incomplete-init.ll
index 716060872ddbb..81cc4fcbfe899 100644
--- a/llvm/test/CodeGen/NVPTX/global-incomplete-init.ll
+++ b/llvm/test/CodeGen/NVPTX/global-incomplete-init.ll
@@ -17,6 +17,6 @@
 
 ; initializer with a symbol, the last 0 could be default initialized
 ; CHECK-DAG: .u8 e = 1;
-; CHECK-DAG: .u64 D[4] = {e, 0, e, 0};
+; CHECK-DAG: .u64 D[4] = {e, 0, e};
 @e = addrspace(1) global i8 1
 @D = addrspace(1) global [4 x ptr addrspace(1)] [ptr addrspace(1) @e, ptr addrspace(1) null, ptr addrspace(1) @e, ptr addrspace(1) null]
diff --git a/llvm/test/CodeGen/NVPTX/packed-aggr.ll b/llvm/test/CodeGen/NVPTX/packed-aggr.ll
index 2065b1a35f326..656a2e9801b37 100644
--- a/llvm/test/CodeGen/NVPTX/packed-aggr.ll
+++ b/llvm/test/CodeGen/NVPTX/packed-aggr.ll
@@ -35,7 +35,7 @@ declare void @func()
 ; CHECK-SAME:   0xFF(generic(p)+3), 0xFF00(generic(p)+3), 0xFF0000(generic(p)+3), 0xFF000000(generic(p)+3),
 ; CHECK64-SAME: 0xFF00000000(generic(p)+3), 0xFF0000000000(generic(p)+3), 0xFF000000000000(generic(p)+3), 0xFF00000000000000(generic(p)+3),
     i32 56 }>, align 1
-; CHECK-SAME:   56, 0, 0, 0};
+; CHECK-SAME:   56};
 
 ;; Test a case than an unaligned pointer is in a nested struct.
 
@@ -51,7 +51,7 @@ declare void @func()
 ; CHECK64-SAME: 0xFF00000000(func), 0xFF0000000000(func), 0xFF000000000000(func), 0xFF00000000000000(func),
     i32 34}
 ; CHECK-SAME:   0, 0, 0,
-; CHECK-SAME:   34, 0, 0, 0};
+; CHECK-SAME:   34};
 
 ;; Test that a packed struct which size is not multiple of the pointer size
 ;; is printed in bytes and uses the mask() operator for pointers even though
@@ -76,7 +76,7 @@ declare void @func()
     ptr @func,
 ; CHECK-SAME:   func,
     i64 15}>, align 1
-; CHECK32-SAME: 15, 0};
+; CHECK32-SAME: 15};
 ; CHECK64-SAME: 15};
 
 ;; Test that a packed struct with unaligned pointers inside an array is handled.
@@ -85,14 +85,14 @@ declare void @func()
 @a5 = addrspace(1) global [2 x %t5] [%t5 <{ ptr @func, i16 5 }>, %t5 <{ ptr @func, i16 9 }> ]
 ; CHECK32: .global .align 8 .u8 a5[12] = {
 ; CHECK32-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func), 5, 0,
-; CHECK32-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func), 9, 0};
+; CHECK32-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func), 9};
 ; CHECK64: .global .align 8 .u8 a5[20] = {
 ; CHECK64-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func),
 ; CHECK64-SAME: 0xFF00000000(func), 0xFF0000000000(func), 0xFF000000000000(func), 0xFF00000000000000(func),
 ; CHECK64-SAME: 5, 0,
 ; CHECK64-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func),
 ; CHECK64-SAME: 0xFF00000000(func), 0xFF0000000000(func), 0xFF000000000000(func), 0xFF00000000000000(func),
-; CHECK64-SAME: 9, 0};
+; CHECK64-SAME: 9};
 
 ;; Test that self-referential packed aggregates also use masked relocations
 ;; when the aggregate size is not a multiple of the pointer size.
@@ -108,3 +108,14 @@ declare void @func()
 ; CHECK64-SAME: 0xFF00000000(generic(self_packed)+3), 0xFF0000000000(generic(self_packed)+3), 0xFF000000000000(generic(self_packed)+3), 0xFF00000000000000(generic(self_packed)+3), 7};
   ptr addrspacecast (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) @self_packed, i32 3) to ptr),
   i8 7 }>, align 1
+
+;; Test that a symbol followed only by zeros is not mistaken for its zero-filled
+;; placeholder when trimming an unaligned aggregate initializer.
+
+%t7 = type <{ i8, ptr, [3 x i8] }>
+ at s7 = addrspace(1) global %t7 <{ i8 1, ptr @func, [3 x i8] zeroinitializer }>, align 1
+; CHECK32: .global .align 1 .u8 s7[8] = {1,
+; CHECK32-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func)};
+; CHECK64: .global .align 1 .u8 s7[12] = {1,
+; CHECK64-SAME: 0xFF(func), 0xFF00(func), 0xFF0000(func), 0xFF000000(func),
+; CHECK64-SAME: 0xFF00000000(func), 0xFF0000000000(func), 0xFF000000000000(func), 0xFF00000000000000(func)};



More information about the llvm-commits mailing list