[llvm] [SPARC] Emit a TRUNCATE when combining truncating BSWAP-STOREs (PR #210483)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 31 10:19:05 PDT 2026


https://github.com/koachan updated https://github.com/llvm/llvm-project/pull/210483

>From e79a072e3cde17af1ee8e6eb301d469a967a3b04 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 18 Jul 2026 11:42:57 +0700
Subject: [PATCH 1/3] [SPARC] Emit a TRUNCATE when combining truncating
 BSWAP-STOREs

Failure to cause this will result in narrower STORE_BIG/LITTLE being fed
with a wider operand, causing instruction selection to fail.

Also, for completeness, add variants of extending/truncating ops
for LOAD-BSWAP pairs too.
---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp |   3 +
 llvm/test/CodeGen/SPARC/bswap.ll            | 279 ++++++++++++++++++++
 2 files changed, 282 insertions(+)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index c45babaec5dc2..96a7ae75bd541 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -3333,6 +3333,9 @@ SDValue SparcTargetLowering::PerformSTORECombine(SDNode *N,
       unsigned Shift = VT.getSizeInBits() - MemVT.getSizeInBits();
       BSwapOp = DAG.getNode(ISD::SRL, DL, VT, BSwapOp,
                             DAG.getShiftAmountConstant(Shift, VT, DL));
+      // Need to truncate if this is a bswap of i64 stored as i32/i16.
+      if (VT == MVT::i64)
+        BSwapOp = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, BSwapOp);
     }
 
     SDValue Ops[] = {N->getOperand(0), BSwapOp, N->getOperand(2),
diff --git a/llvm/test/CodeGen/SPARC/bswap.ll b/llvm/test/CodeGen/SPARC/bswap.ll
index e63efcec77101..ea82e6df8831f 100644
--- a/llvm/test/CodeGen/SPARC/bswap.ll
+++ b/llvm/test/CodeGen/SPARC/bswap.ll
@@ -403,6 +403,140 @@ define i64 @u64_bswapload_misaligned(ptr %0) #0 {
   ret i64 %3
 }
 
+define i16 @u16_bswapload_truncated(ptr %0) #0 {
+; SPARC32-LABEL: u16_bswapload_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %o0, 2, %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    lduha [%o0] #ASI_P_L, %o0
+;
+; SPARCEL-LABEL: u16_bswapload_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    lduha [%o0] #ASI_P, %o0
+;
+; SPARC64-LABEL: u16_bswapload_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %o0, 2, %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    lduha [%o0] #ASI_P_L, %o0
+  %2 = load i32, ptr %0, align 4
+  %3 = trunc i32 %2 to i16
+  %4 = tail call i16 @llvm.bswap.i16(i16 %3)
+  ret i16 %4
+}
+
+define i32 @u32_bswapload_truncated(ptr %0) #0 {
+; SPARC32-LABEL: u32_bswapload_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %o0, 4, %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    lda [%o0] #ASI_P_L, %o0
+;
+; SPARCEL-LABEL: u32_bswapload_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    lda [%o0] #ASI_P, %o0
+;
+; SPARC64-LABEL: u32_bswapload_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %o0, 4, %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    lda [%o0] #ASI_P_L, %o0
+  %2 = load i64, ptr %0, align 8
+  %3 = trunc i64 %2 to i32
+  %4 = tail call i32 @llvm.bswap.i32(i32 %3)
+  ret i32 %4
+}
+
+define i16 @u16_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u16_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    ldub [%o0], %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    sll %o0, 8, %o0
+;
+; SPARCEL-LABEL: u16_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    ldub [%o0], %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    sll %o0, 8, %o0
+;
+; SPARC64-LABEL: u16_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    ldub [%o0], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    sll %o0, 8, %o0
+  %2 = load i8, ptr %0, align 1
+  %3 = zext i8 %2 to i16
+  %4 = tail call i16 @llvm.bswap.i16(i16 %3)
+  ret i16 %4
+}
+
+define i32 @u32_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u32_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    lduh [%o0], %o0
+; SPARC32-NEXT:    add %sp, 92, %o1
+; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+92], %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 96, %sp
+;
+; SPARCEL-LABEL: u32_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    lduh [%o0], %o0
+; SPARCEL-NEXT:    add %sp, 92, %o1
+; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+92], %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 96, %sp
+;
+; SPARC64-LABEL: u32_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    lduh [%o0], %o0
+; SPARC64-NEXT:    add %sp, 2187, %o1
+; SPARC64-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    ld [%sp+2187], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = load i16, ptr %0, align 2
+  %3 = zext i16 %2 to i32
+  %4 = tail call i32 @llvm.bswap.i32(i32 %3)
+  ret i32 %4
+}
+
+define i64 @u64_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u64_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    lda [%o0] #ASI_P_L, %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    mov %g0, %o1
+;
+; SPARCEL-LABEL: u64_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    lda [%o0] #ASI_P, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    mov %g0, %o0
+;
+; SPARC64-LABEL: u64_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    ld [%o0], %o0
+; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    stxa %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    ldx [%sp+2183], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = load i32, ptr %0, align 4
+  %3 = zext i32 %2 to i64
+  %4 = tail call i64 @llvm.bswap.i64(i64 %3)
+  ret i64 %4
+}
+
 define void @u16_bswapstore(ptr %0, i16 %1) #0 {
 ; SPARC32-LABEL: u16_bswapstore:
 ; SPARC32:       ! %bb.0:
@@ -667,4 +801,149 @@ define void @u64_bswapstore_misaligned(ptr %0, i64 %1) #0 {
   ret void
 }
 
+define void @u16_bswapstore_extended(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16_bswapstore_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    add %sp, 92, %o2
+; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC32-NEXT:    lduh [%sp+92], %o1
+; SPARC32-NEXT:    st %o1, [%o0]
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 96, %sp
+;
+; SPARCEL-LABEL: u16_bswapstore_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    add %sp, 92, %o2
+; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
+; SPARCEL-NEXT:    or %o2, 2, %o1
+; SPARCEL-NEXT:    lduh [%o1], %o1
+; SPARCEL-NEXT:    st %o1, [%o0]
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 96, %sp
+;
+; SPARC64-LABEL: u16_bswapstore_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2187, %o2
+; SPARC64-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC64-NEXT:    lduh [%sp+2187], %o1
+; SPARC64-NEXT:    st %o1, [%o0]
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %3 = tail call i16 @llvm.bswap.i16(i16 %1)
+  %4 = zext i16 %3 to i32
+  store i32 %4, ptr %0, align 4
+  ret void
+}
+
+define void @u32_bswapstore_extended(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32_bswapstore_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    add %sp, 92, %o2
+; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+92], %o3
+; SPARC32-NEXT:    mov %g0, %o2
+; SPARC32-NEXT:    std %o2, [%o0]
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 96, %sp
+;
+; SPARCEL-LABEL: u32_bswapstore_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    add %sp, 92, %o2
+; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+92], %o2
+; SPARCEL-NEXT:    mov %g0, %o3
+; SPARCEL-NEXT:    std %o2, [%o0]
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 96, %sp
+;
+; SPARC64-LABEL: u32_bswapstore_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2187, %o2
+; SPARC64-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC64-NEXT:    ld [%sp+2187], %o1
+; SPARC64-NEXT:    stx %o1, [%o0]
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %3 = tail call i32 @llvm.bswap.i32(i32 %1)
+  %4 = zext i32 %3 to i64
+  store i64 %4, ptr %0, align 8
+  ret void
+}
+
+define void @u16_bswapstore_truncated(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    srl %o1, 8, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stb %o1, [%o0]
+;
+; SPARCEL-LABEL: u16_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    srl %o1, 8, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stb %o1, [%o0]
+;
+; SPARC64-LABEL: u16_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srl %o1, 8, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stb %o1, [%o0]
+  %3 = tail call i16 @llvm.bswap.i16(i16 %1)
+  %4 = trunc i16 %3 to i8
+  store i8 %4, ptr %0, align 1
+  ret void
+}
+
+define void @u32_bswapstore_truncated(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    srl %o1, 16, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stha %o1, [%o0] #ASI_P_L
+;
+; SPARCEL-LABEL: u32_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    srl %o1, 16, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stha %o1, [%o0] #ASI_P
+;
+; SPARC64-LABEL: u32_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srl %o1, 16, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stha %o1, [%o0] #ASI_P_L
+  %3 = tail call i32 @llvm.bswap.i32(i32 %1)
+  %4 = trunc i32 %3 to i16
+  store i16 %4, ptr %0, align 2
+  ret void
+}
+
+define void @u64_bswapstore_truncated(ptr %0, i64 %1) #0 {
+; SPARC32-LABEL: u64_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    sta %o1, [%o0] #ASI_P_L
+;
+; SPARCEL-LABEL: u64_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    sta %o2, [%o0] #ASI_P
+;
+; SPARC64-LABEL: u64_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srlx %o1, 32, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    sta %o1, [%o0] #ASI_P_L
+  %3 = tail call i64 @llvm.bswap.i64(i64 %1)
+  %4 = trunc i64 %3 to i32
+  store i32 %4, ptr %0, align 4
+  ret void
+}
+
 attributes #0 = { nounwind }

>From 1d4cb97f23876f1e9ac7c74ca63b1c1c1a4f0398 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sun, 19 Jul 2026 10:57:45 +0700
Subject: [PATCH 2/3] Add more truncating/extending tests

---
 llvm/test/CodeGen/SPARC/bswap.ll | 302 +++++++++++++++++++++++++++----
 1 file changed, 262 insertions(+), 40 deletions(-)

diff --git a/llvm/test/CodeGen/SPARC/bswap.ll b/llvm/test/CodeGen/SPARC/bswap.ll
index ea82e6df8831f..5e3417617ce8e 100644
--- a/llvm/test/CodeGen/SPARC/bswap.ll
+++ b/llvm/test/CodeGen/SPARC/bswap.ll
@@ -403,19 +403,19 @@ define i64 @u64_bswapload_misaligned(ptr %0) #0 {
   ret i64 %3
 }
 
-define i16 @u16_bswapload_truncated(ptr %0) #0 {
-; SPARC32-LABEL: u16_bswapload_truncated:
+define i16 @u32tou16_bswapload_truncated(ptr %0) #0 {
+; SPARC32-LABEL: u32tou16_bswapload_truncated:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    add %o0, 2, %o0
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    lduha [%o0] #ASI_P_L, %o0
 ;
-; SPARCEL-LABEL: u16_bswapload_truncated:
+; SPARCEL-LABEL: u32tou16_bswapload_truncated:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    lduha [%o0] #ASI_P, %o0
 ;
-; SPARC64-LABEL: u16_bswapload_truncated:
+; SPARC64-LABEL: u32tou16_bswapload_truncated:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %o0, 2, %o0
 ; SPARC64-NEXT:    retl
@@ -426,19 +426,42 @@ define i16 @u16_bswapload_truncated(ptr %0) #0 {
   ret i16 %4
 }
 
-define i32 @u32_bswapload_truncated(ptr %0) #0 {
-; SPARC32-LABEL: u32_bswapload_truncated:
+define i16 @u64tou16_bswapload_truncated(ptr %0) #0 {
+; SPARC32-LABEL: u64tou16_bswapload_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %o0, 6, %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    lduha [%o0] #ASI_P_L, %o0
+;
+; SPARCEL-LABEL: u64tou16_bswapload_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    lduha [%o0] #ASI_P, %o0
+;
+; SPARC64-LABEL: u64tou16_bswapload_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %o0, 6, %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    lduha [%o0] #ASI_P_L, %o0
+  %2 = load i64, ptr %0, align 8
+  %3 = trunc i64 %2 to i16
+  %4 = tail call i16 @llvm.bswap.i16(i16 %3)
+  ret i16 %4
+}
+
+define i32 @u64tou32_bswapload_truncated(ptr %0) #0 {
+; SPARC32-LABEL: u64tou32_bswapload_truncated:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    add %o0, 4, %o0
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    lda [%o0] #ASI_P_L, %o0
 ;
-; SPARCEL-LABEL: u32_bswapload_truncated:
+; SPARCEL-LABEL: u64tou32_bswapload_truncated:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    lda [%o0] #ASI_P, %o0
 ;
-; SPARC64-LABEL: u32_bswapload_truncated:
+; SPARC64-LABEL: u64tou32_bswapload_truncated:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %o0, 4, %o0
 ; SPARC64-NEXT:    retl
@@ -449,20 +472,20 @@ define i32 @u32_bswapload_truncated(ptr %0) #0 {
   ret i32 %4
 }
 
-define i16 @u16_bswapload_extended(ptr %0) #0 {
-; SPARC32-LABEL: u16_bswapload_extended:
+define i16 @u8tou16_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u8tou16_bswapload_extended:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    ldub [%o0], %o0
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    sll %o0, 8, %o0
 ;
-; SPARCEL-LABEL: u16_bswapload_extended:
+; SPARCEL-LABEL: u8tou16_bswapload_extended:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    ldub [%o0], %o0
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    sll %o0, 8, %o0
 ;
-; SPARC64-LABEL: u16_bswapload_extended:
+; SPARC64-LABEL: u8tou16_bswapload_extended:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    ldub [%o0], %o0
 ; SPARC64-NEXT:    retl
@@ -473,8 +496,58 @@ define i16 @u16_bswapload_extended(ptr %0) #0 {
   ret i16 %4
 }
 
-define i32 @u32_bswapload_extended(ptr %0) #0 {
-; SPARC32-LABEL: u32_bswapload_extended:
+define i32 @u8tou32_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u8tou32_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    ldub [%o0], %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    sll %o0, 24, %o0
+;
+; SPARCEL-LABEL: u8tou32_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    ldub [%o0], %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    sll %o0, 24, %o0
+;
+; SPARC64-LABEL: u8tou32_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    ldub [%o0], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    sll %o0, 24, %o0
+  %2 = load i8, ptr %0, align 1
+  %3 = zext i8 %2 to i32
+  %4 = tail call i32 @llvm.bswap.i32(i32 %3)
+  ret i32 %4
+}
+
+define i64 @u8tou64_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u8tou64_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    ldub [%o0], %o0
+; SPARC32-NEXT:    sll %o0, 24, %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    mov %g0, %o1
+;
+; SPARCEL-LABEL: u8tou64_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    ldub [%o0], %o0
+; SPARCEL-NEXT:    sll %o0, 24, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    mov %g0, %o0
+;
+; SPARC64-LABEL: u8tou64_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    ldub [%o0], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    sllx %o0, 56, %o0
+  %2 = load i8, ptr %0, align 1
+  %3 = zext i8 %2 to i64
+  %4 = tail call i64 @llvm.bswap.i64(i64 %3)
+  ret i64 %4
+}
+
+define i32 @u16tou32_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u16tou32_bswapload_extended:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    add %sp, -96, %sp
 ; SPARC32-NEXT:    lduh [%o0], %o0
@@ -484,7 +557,7 @@ define i32 @u32_bswapload_extended(ptr %0) #0 {
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    add %sp, 96, %sp
 ;
-; SPARCEL-LABEL: u32_bswapload_extended:
+; SPARCEL-LABEL: u16tou32_bswapload_extended:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    add %sp, -96, %sp
 ; SPARCEL-NEXT:    lduh [%o0], %o0
@@ -494,7 +567,7 @@ define i32 @u32_bswapload_extended(ptr %0) #0 {
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    add %sp, 96, %sp
 ;
-; SPARC64-LABEL: u32_bswapload_extended:
+; SPARC64-LABEL: u16tou32_bswapload_extended:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
 ; SPARC64-NEXT:    lduh [%o0], %o0
@@ -509,20 +582,58 @@ define i32 @u32_bswapload_extended(ptr %0) #0 {
   ret i32 %4
 }
 
-define i64 @u64_bswapload_extended(ptr %0) #0 {
-; SPARC32-LABEL: u64_bswapload_extended:
+define i64 @u16tou64_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u16tou64_bswapload_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    lduh [%o0], %o0
+; SPARC32-NEXT:    add %sp, 92, %o1
+; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+92], %o0
+; SPARC32-NEXT:    mov %g0, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 96, %sp
+;
+; SPARCEL-LABEL: u16tou64_bswapload_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    lduh [%o0], %o0
+; SPARCEL-NEXT:    add %sp, 92, %o1
+; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+92], %o1
+; SPARCEL-NEXT:    mov %g0, %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 96, %sp
+;
+; SPARC64-LABEL: u16tou64_bswapload_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    lduh [%o0], %o0
+; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    stxa %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    ldx [%sp+2183], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = load i16, ptr %0, align 2
+  %3 = zext i16 %2 to i64
+  %4 = tail call i64 @llvm.bswap.i64(i64 %3)
+  ret i64 %4
+}
+
+define i64 @u32tou64_bswapload_extended(ptr %0) #0 {
+; SPARC32-LABEL: u32tou64_bswapload_extended:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    lda [%o0] #ASI_P_L, %o0
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    mov %g0, %o1
 ;
-; SPARCEL-LABEL: u64_bswapload_extended:
+; SPARCEL-LABEL: u32tou64_bswapload_extended:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    lda [%o0] #ASI_P, %o1
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    mov %g0, %o0
 ;
-; SPARC64-LABEL: u64_bswapload_extended:
+; SPARC64-LABEL: u32tou64_bswapload_extended:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
 ; SPARC64-NEXT:    ld [%o0], %o0
@@ -801,8 +912,8 @@ define void @u64_bswapstore_misaligned(ptr %0, i64 %1) #0 {
   ret void
 }
 
-define void @u16_bswapstore_extended(ptr %0, i16 %1) #0 {
-; SPARC32-LABEL: u16_bswapstore_extended:
+define void @u16tou32_bswapstore_extended(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16tou32_bswapstore_extended:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    add %sp, -96, %sp
 ; SPARC32-NEXT:    add %sp, 92, %o2
@@ -812,7 +923,7 @@ define void @u16_bswapstore_extended(ptr %0, i16 %1) #0 {
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    add %sp, 96, %sp
 ;
-; SPARCEL-LABEL: u16_bswapstore_extended:
+; SPARCEL-LABEL: u16tou32_bswapstore_extended:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    add %sp, -96, %sp
 ; SPARCEL-NEXT:    add %sp, 92, %o2
@@ -823,7 +934,7 @@ define void @u16_bswapstore_extended(ptr %0, i16 %1) #0 {
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    add %sp, 96, %sp
 ;
-; SPARC64-LABEL: u16_bswapstore_extended:
+; SPARC64-LABEL: u16tou32_bswapstore_extended:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
 ; SPARC64-NEXT:    add %sp, 2187, %o2
@@ -838,8 +949,47 @@ define void @u16_bswapstore_extended(ptr %0, i16 %1) #0 {
   ret void
 }
 
-define void @u32_bswapstore_extended(ptr %0, i32 %1) #0 {
-; SPARC32-LABEL: u32_bswapstore_extended:
+define void @u16tou64_bswapstore_extended(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16tou64_bswapstore_extended:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    add %sp, 92, %o2
+; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC32-NEXT:    lduh [%sp+92], %o3
+; SPARC32-NEXT:    mov %g0, %o2
+; SPARC32-NEXT:    std %o2, [%o0]
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 96, %sp
+;
+; SPARCEL-LABEL: u16tou64_bswapstore_extended:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    add %sp, 92, %o2
+; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
+; SPARCEL-NEXT:    or %o2, 2, %o1
+; SPARCEL-NEXT:    lduh [%o1], %o2
+; SPARCEL-NEXT:    mov %g0, %o3
+; SPARCEL-NEXT:    std %o2, [%o0]
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 96, %sp
+;
+; SPARC64-LABEL: u16tou64_bswapstore_extended:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2187, %o2
+; SPARC64-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC64-NEXT:    lduh [%sp+2187], %o1
+; SPARC64-NEXT:    stx %o1, [%o0]
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %3 = tail call i16 @llvm.bswap.i16(i16 %1)
+  %4 = zext i16 %3 to i64
+  store i64 %4, ptr %0, align 8
+  ret void
+}
+
+define void @u32tou64_bswapstore_extended(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32tou64_bswapstore_extended:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    add %sp, -96, %sp
 ; SPARC32-NEXT:    add %sp, 92, %o2
@@ -850,7 +1000,7 @@ define void @u32_bswapstore_extended(ptr %0, i32 %1) #0 {
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    add %sp, 96, %sp
 ;
-; SPARCEL-LABEL: u32_bswapstore_extended:
+; SPARCEL-LABEL: u32tou64_bswapstore_extended:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    add %sp, -96, %sp
 ; SPARCEL-NEXT:    add %sp, 92, %o2
@@ -861,7 +1011,7 @@ define void @u32_bswapstore_extended(ptr %0, i32 %1) #0 {
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    add %sp, 96, %sp
 ;
-; SPARC64-LABEL: u32_bswapstore_extended:
+; SPARC64-LABEL: u32tou64_bswapstore_extended:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
 ; SPARC64-NEXT:    add %sp, 2187, %o2
@@ -876,20 +1026,20 @@ define void @u32_bswapstore_extended(ptr %0, i32 %1) #0 {
   ret void
 }
 
-define void @u16_bswapstore_truncated(ptr %0, i16 %1) #0 {
-; SPARC32-LABEL: u16_bswapstore_truncated:
+define void @u16tou8_bswapstore_truncated(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16tou8_bswapstore_truncated:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    srl %o1, 8, %o1
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    stb %o1, [%o0]
 ;
-; SPARCEL-LABEL: u16_bswapstore_truncated:
+; SPARCEL-LABEL: u16tou8_bswapstore_truncated:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    srl %o1, 8, %o1
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    stb %o1, [%o0]
 ;
-; SPARC64-LABEL: u16_bswapstore_truncated:
+; SPARC64-LABEL: u16tou8_bswapstore_truncated:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    srl %o1, 8, %o1
 ; SPARC64-NEXT:    retl
@@ -900,20 +1050,44 @@ define void @u16_bswapstore_truncated(ptr %0, i16 %1) #0 {
   ret void
 }
 
-define void @u32_bswapstore_truncated(ptr %0, i32 %1) #0 {
-; SPARC32-LABEL: u32_bswapstore_truncated:
+define void @u32tou8_bswapstore_truncated(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32tou8_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    srl %o1, 24, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stb %o1, [%o0]
+;
+; SPARCEL-LABEL: u32tou8_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    srl %o1, 24, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stb %o1, [%o0]
+;
+; SPARC64-LABEL: u32tou8_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srl %o1, 24, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stb %o1, [%o0]
+  %3 = tail call i32 @llvm.bswap.i32(i32 %1)
+  %4 = trunc i32 %3 to i8
+  store i8 %4, ptr %0, align 1
+  ret void
+}
+
+define void @u32tou16_bswapstore_truncated(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32tou16_bswapstore_truncated:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    srl %o1, 16, %o1
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    stha %o1, [%o0] #ASI_P_L
 ;
-; SPARCEL-LABEL: u32_bswapstore_truncated:
+; SPARCEL-LABEL: u32tou16_bswapstore_truncated:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    srl %o1, 16, %o1
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    stha %o1, [%o0] #ASI_P
 ;
-; SPARC64-LABEL: u32_bswapstore_truncated:
+; SPARC64-LABEL: u32tou16_bswapstore_truncated:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    srl %o1, 16, %o1
 ; SPARC64-NEXT:    retl
@@ -924,18 +1098,66 @@ define void @u32_bswapstore_truncated(ptr %0, i32 %1) #0 {
   ret void
 }
 
-define void @u64_bswapstore_truncated(ptr %0, i64 %1) #0 {
-; SPARC32-LABEL: u64_bswapstore_truncated:
+define void @u64tou8_bswapstore_truncated(ptr %0, i64 %1) #0 {
+; SPARC32-LABEL: u64tou8_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    srl %o1, 24, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stb %o1, [%o0]
+;
+; SPARCEL-LABEL: u64tou8_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    srl %o2, 24, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stb %o1, [%o0]
+;
+; SPARC64-LABEL: u64tou8_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srlx %o1, 56, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stb %o1, [%o0]
+  %3 = tail call i64 @llvm.bswap.i64(i64 %1)
+  %4 = trunc i64 %3 to i8
+  store i8 %4, ptr %0, align 1
+  ret void
+}
+
+define void @u64tou16_bswapstore_truncated(ptr %0, i64 %1) #0 {
+; SPARC32-LABEL: u64tou16_bswapstore_truncated:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    srl %o1, 16, %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stha %o1, [%o0] #ASI_P_L
+;
+; SPARCEL-LABEL: u64tou16_bswapstore_truncated:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    srl %o2, 16, %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stha %o1, [%o0] #ASI_P
+;
+; SPARC64-LABEL: u64tou16_bswapstore_truncated:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    srlx %o1, 48, %o1
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stha %o1, [%o0] #ASI_P_L
+  %3 = tail call i64 @llvm.bswap.i64(i64 %1)
+  %4 = trunc i64 %3 to i16
+  store i16 %4, ptr %0, align 2
+  ret void
+}
+
+define void @u64tou32_bswapstore_truncated(ptr %0, i64 %1) #0 {
+; SPARC32-LABEL: u64tou32_bswapstore_truncated:
 ; SPARC32:       ! %bb.0:
 ; SPARC32-NEXT:    retl
 ; SPARC32-NEXT:    sta %o1, [%o0] #ASI_P_L
 ;
-; SPARCEL-LABEL: u64_bswapstore_truncated:
+; SPARCEL-LABEL: u64tou32_bswapstore_truncated:
 ; SPARCEL:       ! %bb.0:
 ; SPARCEL-NEXT:    retl
 ; SPARCEL-NEXT:    sta %o2, [%o0] #ASI_P
 ;
-; SPARC64-LABEL: u64_bswapstore_truncated:
+; SPARC64-LABEL: u64tou32_bswapstore_truncated:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    srlx %o1, 32, %o1
 ; SPARC64-NEXT:    retl

>From f336be2c0777b64e43446fe2f00c90e2b4e24de0 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 1 Aug 2026 00:18:43 +0700
Subject: [PATCH 3/3] Use i64->i32 and i64->i16 patterns for truncating instead

---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 3 ---
 llvm/lib/Target/Sparc/SparcInstr64Bit.td    | 5 +++++
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 96a7ae75bd541..c45babaec5dc2 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -3333,9 +3333,6 @@ SDValue SparcTargetLowering::PerformSTORECombine(SDNode *N,
       unsigned Shift = VT.getSizeInBits() - MemVT.getSizeInBits();
       BSwapOp = DAG.getNode(ISD::SRL, DL, VT, BSwapOp,
                             DAG.getShiftAmountConstant(Shift, VT, DL));
-      // Need to truncate if this is a bswap of i64 stored as i32/i16.
-      if (VT == MVT::i64)
-        BSwapOp = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, BSwapOp);
     }
 
     SDValue Ops[] = {N->getOperand(0), BSwapOp, N->getOperand(2),
diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
index 5680dcd81ce86..05c18c9f8c26b 100644
--- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td
+++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
@@ -509,6 +509,11 @@ let Predicates = [HasV9, Is64Bit] in {
 
   def : Pat<(SPloadbig    ForceADDRrr:$src, i64), (LDXArr ForceADDRrr:$src, 0x80)>;
   def : Pat<(SPloadlittle ForceADDRrr:$src, i64), (LDXArr ForceADDRrr:$src, 0x88)>;
+
+  def : Pat<(SPstorebig    i64:$val, ForceADDRrr:$dst, i16), (STHArr ForceADDRrr:$dst, $val, 0x80)>;
+  def : Pat<(SPstorelittle i64:$val, ForceADDRrr:$dst, i16), (STHArr ForceADDRrr:$dst, $val, 0x88)>;
+  def : Pat<(SPstorebig    i64:$val, ForceADDRrr:$dst, i32), (STArr  ForceADDRrr:$dst, $val, 0x80)>;
+  def : Pat<(SPstorelittle i64:$val, ForceADDRrr:$dst, i32), (STArr  ForceADDRrr:$dst, $val, 0x88)>;
   def : Pat<(SPstorebig    i64:$val, ForceADDRrr:$dst, i64), (STXArr ForceADDRrr:$dst, $val, 0x80)>;
   def : Pat<(SPstorelittle i64:$val, ForceADDRrr:$dst, i64), (STXArr ForceADDRrr:$dst, $val, 0x88)>;
 }



More information about the llvm-commits mailing list