[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