[llvm] [AMDGPU] Add folding ISD::SELECT from vXiY into vZi32 with X * Y = Z * 32 (PR #173328)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 17:58:34 PST 2026


https://github.com/Shoreshen updated https://github.com/llvm/llvm-project/pull/173328

>From f4b15af87917f8fbfa91698fbef33e4497305670 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 23 Dec 2025 10:05:31 +0800
Subject: [PATCH 01/19] Try to simplify select v32i4 case by legalizing v16i4

---
 llvm/include/llvm/CodeGen/ValueTypes.td    |  2 ++
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp  |  2 +-
 llvm/test/CodeGen/AMDGPU/select-vectors.ll | 15 +++++++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td
index 74ea86774a8ee..3ef87dc38a85d 100644
--- a/llvm/include/llvm/CodeGen/ValueTypes.td
+++ b/llvm/include/llvm/CodeGen/ValueTypes.td
@@ -113,6 +113,8 @@ def v4096i1 : VTVec<4096, i1>; // 4096 x i1 vector value
 def v128i2  : VTVec<128,  i2>; //  128 x i2 vector value
 def v256i2  : VTVec<256,  i2>; //  256 x i2 vector value
 
+def v16i4   : VTVec<16,   i4>; //   16 x i4 vector value
+def v32i4   : VTVec<32,   i4>; //   32 x i4 vector value
 def v64i4   : VTVec<64,   i4>; //   64 x i4 vector value
 def v128i4  : VTVec<128,  i4>; //  128 x i4 vector value
 
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 102ca92856bae..03d4f9c09dc2a 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -876,7 +876,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
                      {MVT::v4i16, MVT::v4f16, MVT::v4bf16, MVT::v2i8, MVT::v4i8,
                       MVT::v8i8, MVT::v8i16, MVT::v8f16, MVT::v8bf16,
                       MVT::v16i16, MVT::v16f16, MVT::v16bf16, MVT::v32i16,
-                      MVT::v32f16, MVT::v32bf16},
+                      MVT::v32f16, MVT::v32bf16, MVT::v16i4},
                      Custom);
 
   setOperationAction({ISD::SMULO, ISD::UMULO}, MVT::i64, Custom);
diff --git a/llvm/test/CodeGen/AMDGPU/select-vectors.ll b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
index e754f665c5f43..5e52b2fca32c8 100644
--- a/llvm/test/CodeGen/AMDGPU/select-vectors.ll
+++ b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
@@ -65,6 +65,21 @@ define amdgpu_kernel void @v_select_v16i8(ptr addrspace(1) %out, ptr addrspace(1
   ret void
 }
 
+; GCN-LABEL: {{^}}v_select_v32i4:
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define amdgpu_kernel void @v_select_v32i4(ptr addrspace(1) %out, ptr addrspace(1) %a.ptr, ptr addrspace(4) %b.ptr, i32 %c) #0 {
+  %a = load <32 x i4>, ptr addrspace(1) %a.ptr, align 2
+  %b = load <32 x i4>, ptr addrspace(4) %b.ptr, align 2
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, <32 x i4> %a, <32 x i4> %b
+  store <32 x i4> %select, ptr addrspace(1) %out, align 2
+  ret void
+}
+
 ; GCN-LABEL: {{^}}select_v4i8:
 ; GFX89: s_cselect_b32
 ; GFX89-NOT: s_cselect_b32

>From 8652612ed2be9a2a48de01d81a27d785aeb8bd12 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 25 Dec 2025 17:35:35 +0800
Subject: [PATCH 02/19] fix part of tests

---
 llvm/lib/Target/X86/X86ISelLowering.cpp |  3 +-
 llvm/test/CodeGen/X86/pr15267.ll        | 64 ++-----------------------
 llvm/test/TableGen/CPtrWildcard.td      |  4 +-
 3 files changed, 7 insertions(+), 64 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 811ffb090d751..2f1bab8411ad1 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -2789,7 +2789,8 @@ X86TargetLowering::getPreferredVectorAction(MVT VT) const {
     return TypeSplitVector;
 
   if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
-      VT.getVectorElementType() != MVT::i1)
+      VT.getVectorElementType() != MVT::i1 &&
+      VT.getVectorElementType() != MVT::i4)
     return TypeWidenVector;
 
   return TargetLoweringBase::getPreferredVectorAction(VT);
diff --git a/llvm/test/CodeGen/X86/pr15267.ll b/llvm/test/CodeGen/X86/pr15267.ll
index 5083eac71dce0..7292e24df9d82 100644
--- a/llvm/test/CodeGen/X86/pr15267.ll
+++ b/llvm/test/CodeGen/X86/pr15267.ll
@@ -82,67 +82,9 @@ define <4 x i64> @test3(ptr %in) nounwind {
 define <16 x i4> @test4(ptr %in) nounwind {
 ; CHECK-LABEL: test4:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq (%rdi), %rax
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $4, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    movl %eax, %edx
-; CHECK-NEXT:    andl $15, %edx
-; CHECK-NEXT:    vmovd %edx, %xmm0
-; CHECK-NEXT:    vpinsrb $1, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $8, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $2, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $12, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $3, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $16, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $4, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $20, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $5, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $24, %ecx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $6, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    shrl $28, %ecx
-; CHECK-NEXT:    vpinsrb $7, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $32, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $8, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $36, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $9, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $40, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $10, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $44, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $11, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $48, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $12, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $52, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $13, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    shrq $56, %rcx
-; CHECK-NEXT:    andl $15, %ecx
-; CHECK-NEXT:    vpinsrb $14, %ecx, %xmm0, %xmm0
-; CHECK-NEXT:    shrq $60, %rax
-; CHECK-NEXT:    vpinsrb $15, %eax, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    movq (%rsi), %rcx
+; CHECK-NEXT:    movq %rcx, (%rdi)
 ; CHECK-NEXT:    retq
   %ret = load <16 x i4>, ptr %in, align 1
   ret <16 x i4> %ret
diff --git a/llvm/test/TableGen/CPtrWildcard.td b/llvm/test/TableGen/CPtrWildcard.td
index 867d6f85bdecb..358af86e2d2ef 100644
--- a/llvm/test/TableGen/CPtrWildcard.td
+++ b/llvm/test/TableGen/CPtrWildcard.td
@@ -8,13 +8,13 @@
 // CHECK-NEXT:/*     3*/ OPC_CheckChild0Integer, [[#]],
 // CHECK-NEXT:/*     5*/ OPC_RecordChild1, // #0 = $src
 // CHECK-NEXT:/*     6*/ OPC_Scope, 9, /*->17*/ // 2 children in Scope
-// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/0|128,2/*256*/,
+// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/2|128,2/*258*/,
 // CHECK-NEXT:/*    11*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C64_TO_I64),
 // CHECK-NEXT:                /*MVT::i64*/8, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c64:{ *:[c64] }:$src) - Complexity = 8
 // CHECK-NEXT:            // Dst: (C64_TO_I64:{ *:[i64] } ?:{ *:[c64] }:$src)
 // CHECK-NEXT:/*    17*/ /*Scope*/ 9, /*->27*/
-// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/1|128,2/*257*/,
+// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/3|128,2/*259*/,
 // CHECK-NEXT:/*    21*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C128_TO_I64),
 // CHECK-NEXT:                /*MVT::i64*/8, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c128:{ *:[c128] }:$src) - Complexity = 8

>From 836edd720245914767488f9deb4fb8863d122c0d Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Fri, 26 Dec 2025 10:10:06 +0800
Subject: [PATCH 03/19] fix x86 test case

---
 llvm/lib/Target/X86/X86ISelLowering.cpp |  3 ++
 llvm/test/CodeGen/X86/pr15267.ll        | 64 +++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 2f1bab8411ad1..0edbffbfbeb3c 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -1041,6 +1041,9 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
       if (VT.getVectorElementType() == MVT::f16 ||
           VT.getVectorElementType() == MVT::bf16)
         setLoadExtAction(ISD::EXTLOAD, InnerVT, VT, Expand);
+
+      if (VT.getVectorElementType() == MVT::i4)
+        setLoadExtAction(ISD::EXTLOAD, InnerVT, VT, Expand);
     }
   }
 
diff --git a/llvm/test/CodeGen/X86/pr15267.ll b/llvm/test/CodeGen/X86/pr15267.ll
index 7292e24df9d82..5083eac71dce0 100644
--- a/llvm/test/CodeGen/X86/pr15267.ll
+++ b/llvm/test/CodeGen/X86/pr15267.ll
@@ -82,9 +82,67 @@ define <4 x i64> @test3(ptr %in) nounwind {
 define <16 x i4> @test4(ptr %in) nounwind {
 ; CHECK-LABEL: test4:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq %rdi, %rax
-; CHECK-NEXT:    movq (%rsi), %rcx
-; CHECK-NEXT:    movq %rcx, (%rdi)
+; CHECK-NEXT:    movq (%rdi), %rax
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $4, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    movl %eax, %edx
+; CHECK-NEXT:    andl $15, %edx
+; CHECK-NEXT:    vmovd %edx, %xmm0
+; CHECK-NEXT:    vpinsrb $1, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $8, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $2, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $12, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $3, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $16, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $4, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $20, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $5, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $24, %ecx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $6, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $28, %ecx
+; CHECK-NEXT:    vpinsrb $7, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $32, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $8, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $36, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $9, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $40, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $10, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $44, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $11, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $48, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $12, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $52, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $13, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    shrq $56, %rcx
+; CHECK-NEXT:    andl $15, %ecx
+; CHECK-NEXT:    vpinsrb $14, %ecx, %xmm0, %xmm0
+; CHECK-NEXT:    shrq $60, %rax
+; CHECK-NEXT:    vpinsrb $15, %eax, %xmm0, %xmm0
 ; CHECK-NEXT:    retq
   %ret = load <16 x i4>, ptr %in, align 1
   ret <16 x i4> %ret

>From 2cd9a5d0d4dc922368865f32863b5c38e6535291 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 7 Jan 2026 10:29:29 +0800
Subject: [PATCH 04/19] fix test case

---
 llvm/test/TableGen/CPtrWildcard.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/TableGen/CPtrWildcard.td b/llvm/test/TableGen/CPtrWildcard.td
index 79efc42af9634..e1a7a6e97c76a 100644
--- a/llvm/test/TableGen/CPtrWildcard.td
+++ b/llvm/test/TableGen/CPtrWildcard.td
@@ -8,13 +8,13 @@
 // CHECK-NEXT:/*     3*/ OPC_CheckChild0Integer, [[#]],
 // CHECK-NEXT:/*     5*/ OPC_RecordChild1, // #0 = $src
 // CHECK-NEXT:/*     6*/ OPC_Scope, 9, /*->17*/ // 2 children in Scope
-// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/2|128,2/*258*/,
+// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/4|128,2/*260*/,
 // CHECK-NEXT:/*    11*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C64_TO_I64),
 // CHECK-NEXT:                /*MVT::i64*/8, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c64:{ *:[c64] }:$src) - Complexity = 8
 // CHECK-NEXT:            // Dst: (C64_TO_I64:{ *:[i64] } ?:{ *:[c64] }:$src)
 // CHECK-NEXT:/*    17*/ /*Scope*/ 9, /*->27*/
-// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/3|128,2/*259*/,
+// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/5|128,2/*261*/,
 // CHECK-NEXT:/*    21*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C128_TO_I64),
 // CHECK-NEXT:                /*MVT::i64*/8, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c128:{ *:[c128] }:$src) - Complexity = 8

>From 3cbfe5649bdd5dbf98ff68330dc7ae5bf5ed7709 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 13 Jan 2026 09:28:08 +0800
Subject: [PATCH 05/19] fix test case

---
 llvm/test/TableGen/CPtrWildcard.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/TableGen/CPtrWildcard.td b/llvm/test/TableGen/CPtrWildcard.td
index 163d150f88ab0..a50cd4e133d0e 100644
--- a/llvm/test/TableGen/CPtrWildcard.td
+++ b/llvm/test/TableGen/CPtrWildcard.td
@@ -7,13 +7,13 @@
 // CHECK-NEXT: /*     0*/ OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_WO_CHAIN),
 // CHECK-NEXT:/*     3*/ OPC_CheckChild0Integer, [[#]],
 // CHECK-NEXT:/*     5*/ OPC_RecordChild1, // #0 = $src
-// CHECK-NEXT:/*     6*/ OPC_Scope, 9, /*->17*/ // 2 children in Scope
+// CHECK-NEXT:/* 6*/ OPC_Scope /*2 children */, 9, // ->17 
 // CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/4|128,2/*260*/,
 // CHECK-NEXT:/*    11*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C64_TO_I64),
 // CHECK-NEXT:                MVT::i64, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c64:{ *:[c64] }:$src) - Complexity = 8
 // CHECK-NEXT:            // Dst: (C64_TO_I64:{ *:[i64] } ?:{ *:[c64] }:$src)
-// CHECK-NEXT:/*    17*/ /*Scope*/ 9, /*->27*/
+// CHECK-NEXT:/* 17*/ /*Scope*/ 9, // ->27
 // CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/5|128,2/*261*/,
 // CHECK-NEXT:/*    21*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C128_TO_I64),
 // CHECK-NEXT:                MVT::i64, 1/*#Ops*/, 0,

>From 3ae9fa5e4c52ca56c5e086e25a6ffe6ba0afa060 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 13 Jan 2026 17:47:20 +0800
Subject: [PATCH 06/19] pre convert selet to vZi32

---
 llvm/include/llvm/CodeGen/ValueTypes.td   |  2 -
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 73 ++++++++++++++++++-----
 llvm/lib/Target/AMDGPU/SIISelLowering.h   |  4 ++
 llvm/lib/Target/X86/X86ISelLowering.cpp   |  6 +-
 llvm/test/TableGen/CPtrWildcard.td        |  8 +--
 5 files changed, 67 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td
index 9ca535d9af21d..d7f3c683e2fa2 100644
--- a/llvm/include/llvm/CodeGen/ValueTypes.td
+++ b/llvm/include/llvm/CodeGen/ValueTypes.td
@@ -113,8 +113,6 @@ def v4096i1 : VTVec<4096, i1>; // 4096 x i1 vector value
 def v128i2  : VTVec<128,  i2>; //  128 x i2 vector value
 def v256i2  : VTVec<256,  i2>; //  256 x i2 vector value
 
-def v16i4   : VTVec<16,   i4>; //   16 x i4 vector value
-def v32i4   : VTVec<32,   i4>; //   32 x i4 vector value
 def v64i4   : VTVec<64,   i4>; //   64 x i4 vector value
 def v128i4  : VTVec<128,  i4>; //  128 x i4 vector value
 
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 7fde4ad7497e9..74314a895d7f7 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -877,7 +877,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
                      {MVT::v4i16, MVT::v4f16, MVT::v4bf16, MVT::v2i8, MVT::v4i8,
                       MVT::v8i8, MVT::v8i16, MVT::v8f16, MVT::v8bf16,
                       MVT::v16i16, MVT::v16f16, MVT::v16bf16, MVT::v32i16,
-                      MVT::v32f16, MVT::v32bf16, MVT::v16i4},
+                      MVT::v32f16, MVT::v32bf16},
                      Custom);
 
   setOperationAction({ISD::SMULO, ISD::UMULO}, MVT::i64, Custom);
@@ -16986,20 +16986,16 @@ SDValue SITargetLowering::performClampCombine(SDNode *N,
   return SDValue(CSrc, 0);
 }
 
-SDValue SITargetLowering::performSelectCombine(SDNode *N,
-                                               DAGCombinerInfo &DCI) const {
-
-  // Try to fold CMP + SELECT patterns with shared constants (both FP and
-  // integer).
-  // Detect when CMP and SELECT use the same constant and fold them to avoid
-  // loading the constant twice. Specifically handles patterns like:
-  // %cmp = icmp eq i32 %val, 4242
-  // %sel = select i1 %cmp, i32 4242, i32 %other
-  // It can be optimized to reuse %val instead of 4242 in select.
-  SDValue Cond = N->getOperand(0);
-  SDValue TrueVal = N->getOperand(1);
-  SDValue FalseVal = N->getOperand(2);
-
+// Try to fold CMP + SELECT patterns with shared constants (both FP and
+// integer).
+// Detect when CMP and SELECT use the same constant and fold them to avoid
+// loading the constant twice. Specifically handles patterns like:
+// %cmp = icmp eq i32 %val, 4242
+// %sel = select i1 %cmp, i32 4242, i32 %other
+// It can be optimized to reuse %val instead of 4242 in select.
+SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
+                                               SDValue &Cond, SDValue &TrueVal,
+                                               SDValue &FalseVal) const {
   // Check if condition is a comparison.
   if (Cond.getOpcode() != ISD::SETCC)
     return SDValue();
@@ -17058,6 +17054,53 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
                          SelectLHS, SelectRHS);
 }
 
+// Try to convert vXiY into vZi32 with X * Y = Z * 32
+SDValue SITargetLowering::castTypeSelect(SDNode *N, DAGCombinerInfo &DCI,
+                                         SDValue &Cond, SDValue &TrueVal,
+                                         SDValue &FalseVal) const {
+  if (N->getNumValues() != 1)
+    return SDValue();
+
+  EVT ResultVT = N->getValueType(0);
+  if (ResultVT.isSimple() || !ResultVT.isVector() ||
+      !ResultVT.isPow2VectorType())
+    return SDValue();
+
+  EVT EltVT = ResultVT.getVectorElementType();
+  unsigned EltBitSize = EltVT.getSizeInBits();
+  ElementCount NumElts = ResultVT.getVectorElementCount();
+  if (!EltVT.isInteger() || !isPowerOf2_32(EltBitSize) || NumElts.isScalar())
+    return SDValue();
+
+  unsigned NewNumElts = ResultVT.getVectorNumElements() / (32 / EltBitSize);
+  if (TrueVal.getValueType() == ResultVT &&
+      FalseVal.getValueType() == ResultVT) {
+    EVT NewVT = EVT::getVectorVT(*DCI.DAG.getContext(), MVT::i32, NewNumElts);
+    SDValue NewTrue =
+        DCI.DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
+    SDValue NewFalse =
+        DCI.DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
+    SDValue NewSelect =
+        DCI.DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
+    return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
+  }
+  return SDValue();
+}
+
+SDValue SITargetLowering::performSelectCombine(SDNode *N,
+                                               DAGCombinerInfo &DCI) const {
+
+  SDValue Cond = N->getOperand(0);
+  SDValue TrueVal = N->getOperand(1);
+  SDValue FalseVal = N->getOperand(2);
+
+  SDValue Res = foldShareConstSelect(N, DCI, Cond, TrueVal, FalseVal);
+  if (Res)
+    return Res;
+  else
+    return castTypeSelect(N, DCI, Cond, TrueVal, FalseVal);
+}
+
 SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
                                             DAGCombinerInfo &DCI) const {
   switch (N->getOpcode()) {
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index e82f4528fcd09..31ba200b45831 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -227,6 +227,10 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   SDValue performExtractVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performInsertVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performFPRoundCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+  SDValue foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue &Cond,
+                               SDValue &TrueVal, SDValue &FalseVal) const;
+  SDValue castTypeSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue &Cond,
+                         SDValue &TrueVal, SDValue &FalseVal) const;
   SDValue performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const;
 
   SDValue reassociateScalarOps(SDNode *N, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 13c508d599620..a354704c5958b 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -1050,9 +1050,6 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
       if (VT.getVectorElementType() == MVT::f16 ||
           VT.getVectorElementType() == MVT::bf16)
         setLoadExtAction(ISD::EXTLOAD, InnerVT, VT, Expand);
-
-      if (VT.getVectorElementType() == MVT::i4)
-        setLoadExtAction(ISD::EXTLOAD, InnerVT, VT, Expand);
     }
   }
 
@@ -2800,8 +2797,7 @@ X86TargetLowering::getPreferredVectorAction(MVT VT) const {
     return TypeSplitVector;
 
   if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
-      VT.getVectorElementType() != MVT::i1 &&
-      VT.getVectorElementType() != MVT::i4)
+      VT.getVectorElementType() != MVT::i1)
     return TypeWidenVector;
 
   return TargetLoweringBase::getPreferredVectorAction(VT);
diff --git a/llvm/test/TableGen/CPtrWildcard.td b/llvm/test/TableGen/CPtrWildcard.td
index a50cd4e133d0e..41373b2c2fe4c 100644
--- a/llvm/test/TableGen/CPtrWildcard.td
+++ b/llvm/test/TableGen/CPtrWildcard.td
@@ -7,14 +7,14 @@
 // CHECK-NEXT: /*     0*/ OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_WO_CHAIN),
 // CHECK-NEXT:/*     3*/ OPC_CheckChild0Integer, [[#]],
 // CHECK-NEXT:/*     5*/ OPC_RecordChild1, // #0 = $src
-// CHECK-NEXT:/* 6*/ OPC_Scope /*2 children */, 9, // ->17 
-// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/4|128,2/*260*/,
+// CHECK-NEXT:/*     6*/ OPC_Scope /*2 children */, 9, // ->17
+// CHECK-NEXT:/*     8*/  OPC_CheckChild1Type, /*MVT::c64*/2|128,2/*258*/,
 // CHECK-NEXT:/*    11*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C64_TO_I64),
 // CHECK-NEXT:                MVT::i64, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c64:{ *:[c64] }:$src) - Complexity = 8
 // CHECK-NEXT:            // Dst: (C64_TO_I64:{ *:[i64] } ?:{ *:[c64] }:$src)
-// CHECK-NEXT:/* 17*/ /*Scope*/ 9, // ->27
-// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/5|128,2/*261*/,
+// CHECK-NEXT:/*    17*/ /*Scope*/ 9, // ->27
+// CHECK-NEXT:/*    18*/  OPC_CheckChild1Type, /*MVT::c128*/3|128,2/*259*/,
 // CHECK-NEXT:/*    21*/  OPC_MorphNodeTo1None, TARGET_VAL(MyTarget::C128_TO_I64),
 // CHECK-NEXT:                MVT::i64, 1/*#Ops*/, 0,
 // CHECK-NEXT:            // Src: (intrinsic_wo_chain:{ *:[i64] } [[#]]:{ *:[iPTR] }, c128:{ *:[c128] }:$src) - Complexity = 8

>From d4df9639d6e7a0e7e164ea0da04dd9f1babc7408 Mon Sep 17 00:00:00 2001
From: Shoreshen <372660931 at qq.com>
Date: Wed, 21 Jan 2026 09:41:12 +0800
Subject: [PATCH 07/19] Update llvm/lib/Target/AMDGPU/SIISelLowering.cpp

Co-authored-by: Craig Topper <craig.topper at sifive.com>
---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 9c859c33d89c0..0b8625fd6ce17 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17084,8 +17084,7 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
   SDValue TrueVal = N->getOperand(1);
   SDValue FalseVal = N->getOperand(2);
 
-  SDValue Res = foldShareConstSelect(N, DCI, Cond, TrueVal, FalseVal);
-  if (Res)
+  if (SDValue Res = foldShareConstSelect(N, DCI, Cond, TrueVal, FalseVal))
     return Res;
   else
     return castTypeSelect(N, DCI, Cond, TrueVal, FalseVal);

>From 5f98054adbdd69a1de21c818a8b5eac25f008d1d Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 21 Jan 2026 10:12:20 +0800
Subject: [PATCH 08/19] fix comments

---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 36 ++++++++++-------------
 llvm/lib/Target/AMDGPU/SIISelLowering.h   |  8 ++---
 2 files changed, 19 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index fb9c1ac874baa..3585836cdbaac 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17007,8 +17007,8 @@ SDValue SITargetLowering::performClampCombine(SDNode *N,
 // %sel = select i1 %cmp, i32 4242, i32 %other
 // It can be optimized to reuse %val instead of 4242 in select.
 SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
-                                               SDValue &Cond, SDValue &TrueVal,
-                                               SDValue &FalseVal) const {
+                                               SDValue Cond, SDValue TrueVal,
+                                               SDValue FalseVal) const {
   // Check if condition is a comparison.
   if (Cond.getOpcode() != ISD::SETCC)
     return SDValue();
@@ -17069,11 +17069,8 @@ SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
 
 // Try to convert vXiY into vZi32 with X * Y = Z * 32
 SDValue SITargetLowering::castTypeSelect(SDNode *N, DAGCombinerInfo &DCI,
-                                         SDValue &Cond, SDValue &TrueVal,
-                                         SDValue &FalseVal) const {
-  if (N->getNumValues() != 1)
-    return SDValue();
-
+                                         SDValue Cond, SDValue TrueVal,
+                                         SDValue FalseVal) const {
   EVT ResultVT = N->getValueType(0);
   if (ResultVT.isSimple() || !ResultVT.isVector() ||
       !ResultVT.isPow2VectorType())
@@ -17086,18 +17083,15 @@ SDValue SITargetLowering::castTypeSelect(SDNode *N, DAGCombinerInfo &DCI,
     return SDValue();
 
   unsigned NewNumElts = ResultVT.getVectorNumElements() / (32 / EltBitSize);
-  if (TrueVal.getValueType() == ResultVT &&
-      FalseVal.getValueType() == ResultVT) {
-    EVT NewVT = EVT::getVectorVT(*DCI.DAG.getContext(), MVT::i32, NewNumElts);
-    SDValue NewTrue =
-        DCI.DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
-    SDValue NewFalse =
-        DCI.DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
-    SDValue NewSelect =
-        DCI.DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
-    return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
-  }
-  return SDValue();
+
+  EVT NewVT = EVT::getVectorVT(*DCI.DAG.getContext(), MVT::i32, NewNumElts);
+  SDValue NewTrue =
+      DCI.DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
+  SDValue NewFalse =
+      DCI.DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
+  SDValue NewSelect =
+      DCI.DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
+  return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
 }
 
 SDValue SITargetLowering::performSelectCombine(SDNode *N,
@@ -17109,8 +17103,8 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
 
   if (SDValue Res = foldShareConstSelect(N, DCI, Cond, TrueVal, FalseVal))
     return Res;
-  else
-    return castTypeSelect(N, DCI, Cond, TrueVal, FalseVal);
+
+  return castTypeSelect(N, DCI, Cond, TrueVal, FalseVal);
 }
 
 SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 0885c12f7ff9e..f47068fb72ecb 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -227,10 +227,10 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   SDValue performExtractVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performInsertVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performFPRoundCombine(SDNode *N, DAGCombinerInfo &DCI) const;
-  SDValue foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue &Cond,
-                               SDValue &TrueVal, SDValue &FalseVal) const;
-  SDValue castTypeSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue &Cond,
-                         SDValue &TrueVal, SDValue &FalseVal) const;
+  SDValue foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue Cond,
+                               SDValue TrueVal, SDValue FalseVal) const;
+  SDValue castTypeSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue Cond,
+                         SDValue TrueVal, SDValue FalseVal) const;
   SDValue performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const;
 
   SDValue reassociateScalarOps(SDNode *N, SelectionDAG &DAG) const;

>From 95aa98207859429b88b315c0be5e9d42aea6c341 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 21 Jan 2026 12:08:56 +0800
Subject: [PATCH 09/19] fix comment

---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 3585836cdbaac..8fddca4cad6b6 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17078,12 +17078,14 @@ SDValue SITargetLowering::castTypeSelect(SDNode *N, DAGCombinerInfo &DCI,
 
   EVT EltVT = ResultVT.getVectorElementType();
   unsigned EltBitSize = EltVT.getSizeInBits();
-  ElementCount NumElts = ResultVT.getVectorElementCount();
-  if (!EltVT.isInteger() || !isPowerOf2_32(EltBitSize) || NumElts.isScalar())
+  if (!EltVT.isInteger() || ResultVT.getVectorElementCount().isScalar())
     return SDValue();
 
   unsigned NewNumElts = ResultVT.getVectorNumElements() / (32 / EltBitSize);
 
+  if (NewNumElts * 32 != EltBitSize * ResultVT.getVectorNumElements())
+    return SDValue();
+
   EVT NewVT = EVT::getVectorVT(*DCI.DAG.getContext(), MVT::i32, NewNumElts);
   SDValue NewTrue =
       DCI.DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);

>From 4a54613400b66fabc303f113e786c056bcfd9c51 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Sun, 25 Jan 2026 11:59:07 +0800
Subject: [PATCH 10/19] move to generic DAG combine

---
 llvm/include/llvm/CodeGen/ValueTypes.h        | 25 +++++++
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 29 ++++++++
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 74 ++++---------------
 llvm/lib/Target/AMDGPU/SIISelLowering.h       |  4 -
 llvm/test/CodeGen/AMDGPU/select-vectors.ll    | 41 ++++++++++
 5 files changed, 109 insertions(+), 64 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/ValueTypes.h b/llvm/include/llvm/CodeGen/ValueTypes.h
index 3897cb8c18127..3736c89aaf4c7 100644
--- a/llvm/include/llvm/CodeGen/ValueTypes.h
+++ b/llvm/include/llvm/CodeGen/ValueTypes.h
@@ -447,6 +447,31 @@ namespace llvm {
       return EVT::getVectorVT(Context, EltVT, getVectorElementCount());
     }
 
+    /// Return a vector type with integer elements of the specified width,
+    /// keeping the total bit-width constant. The element count is adjusted
+    /// such that OldElementCount * OldElementWidth == NewElementCount *
+    /// NewEltWidth. Returns an invalid EVT if the type is not a vector, not an
+    /// integer vector, or if the total bits are not evenly divisible by the new
+    /// element width.
+    EVT getIntegerVectorWithElementWidth(LLVMContext &Context,
+                                         unsigned NewEltWidth) const {
+      if (!isVector() || !isInteger())
+        return EVT();
+
+      unsigned TotalBits = getVectorMinNumElements() * getScalarSizeInBits();
+      if (TotalBits % NewEltWidth != 0)
+        return EVT();
+
+      unsigned NewNumElements = TotalBits / NewEltWidth;
+      EVT NewEltVT = EVT::getIntegerVT(Context, NewEltWidth);
+
+      // Preserve scalability
+      ElementCount EC = getVectorElementCount();
+      ElementCount NewEC = ElementCount::get(NewNumElements, EC.isScalable());
+
+      return EVT::getVectorVT(Context, NewEltVT, NewEC);
+    }
+
     // Return a VT for a vector type with the same element type but
     // half the number of elements. The type returned may be an
     // extended type.
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index cd505bd021f41..bb21e7a8deaac 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6972,6 +6972,32 @@ static SDValue combineSelectAsExtAnd(SDValue Cond, SDValue T, SDValue F,
   return DAG.getNode(ISD::AND, DL, OpVT, CondMask, T.getOperand(0));
 }
 
+// Try to convert vXiY into vZi32 with X * Y = Z * 32
+// This prevent promotion of integer vectors like v32i4 to v32i16
+// which can create extra operations on type casting.
+static SDValue castTypeSelect(SDNode *N, SelectionDAG &DAG, SDValue Cond,
+                              SDValue TrueVal, SDValue FalseVal) {
+  EVT ResultVT = N->getValueType(0);
+  if (ResultVT.isSimple() || !ResultVT.isVector() ||
+      !ResultVT.isPow2VectorType())
+    return SDValue();
+
+  EVT EltVT = ResultVT.getVectorElementType();
+  if (!EltVT.isInteger() || ResultVT.getVectorElementCount().isScalar())
+    return SDValue();
+
+  EVT NewVT = ResultVT.getIntegerVectorWithElementWidth(*DAG.getContext(), 32);
+  if (NewVT == EVT())
+    return SDValue();
+
+  SDValue NewTrue = DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
+  SDValue NewFalse =
+      DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
+  SDValue NewSelect =
+      DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
+  return DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
+}
+
 /// This contains all DAGCombine rules which reduce two values combined by
 /// an And operation to a single value. This makes them reusable in the context
 /// of visitSELECT(). Rules involving constants are not included as
@@ -12764,6 +12790,9 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
   if (SDValue R = combineSelectAsExtAnd(N0, N1, N2, DL, DAG))
     return R;
 
+  if (SDValue R = castTypeSelect(N, DAG, N0, N1, N2))
+    return R;
+
   return SDValue();
 }
 
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 34da2752053df..c1c93cc1ce3c5 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17005,36 +17005,35 @@ SDValue SITargetLowering::performClampCombine(SDNode *N,
   return SDValue(CSrc, 0);
 }
 
-// Try to fold CMP + SELECT patterns with shared constants (both FP and
-// integer).
-// Detect when CMP and SELECT use the same constant and fold them to avoid
-// loading the constant twice. Specifically handles patterns like:
-// %cmp = icmp eq i32 %val, 4242
-// %sel = select i1 %cmp, i32 4242, i32 %other
-// It can be optimized to reuse %val instead of 4242 in select.
-SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
-                                               SDValue Cond, SDValue TrueVal,
-                                               SDValue FalseVal) const {
+SDValue SITargetLowering::performSelectCombine(SDNode *N,
+                                               DAGCombinerInfo &DCI) const {
+
+  // Try to fold CMP + SELECT patterns with shared constants (both FP and
+  // integer).
+  // Detect when CMP and SELECT use the same constant and fold them to avoid
+  // loading the constant twice. Specifically handles patterns like:
+  // %cmp = icmp eq i32 %val, 4242
+  // %sel = select i1 %cmp, i32 4242, i32 %other
+  // It can be optimized to reuse %val instead of 4242 in select.
+  SDValue Cond = N->getOperand(0);
+  SDValue TrueVal = N->getOperand(1);
+  SDValue FalseVal = N->getOperand(2);
+
   // Check if condition is a comparison.
   if (Cond.getOpcode() != ISD::SETCC)
     return SDValue();
-
   SDValue LHS = Cond.getOperand(0);
   SDValue RHS = Cond.getOperand(1);
   ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
-
   bool isFloatingPoint = LHS.getValueType().isFloatingPoint();
   bool isInteger = LHS.getValueType().isInteger();
-
   // Handle simple floating-point and integer types only.
   if (!isFloatingPoint && !isInteger)
     return SDValue();
-
   bool isEquality = CC == (isFloatingPoint ? ISD::SETOEQ : ISD::SETEQ);
   bool isNonEquality = CC == (isFloatingPoint ? ISD::SETONE : ISD::SETNE);
   if (!isEquality && !isNonEquality)
     return SDValue();
-
   SDValue ArgVal, ConstVal;
   if ((isFloatingPoint && isa<ConstantFPSDNode>(RHS)) ||
       (isInteger && isa<ConstantSDNode>(RHS))) {
@@ -17047,7 +17046,6 @@ SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
   } else {
     return SDValue();
   }
-
   // Skip optimization for inlinable immediates.
   if (isFloatingPoint) {
     const APFloat &Val = cast<ConstantFPSDNode>(ConstVal)->getValueAPF();
@@ -17058,14 +17056,12 @@ SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
             cast<ConstantSDNode>(ConstVal)->getSExtValue()))
       return SDValue();
   }
-
   // For equality and non-equality comparisons, patterns:
   // select (setcc x, const), const, y -> select (setcc x, const), x, y
   // select (setccinv x, const), y, const -> select (setccinv x, const), y, x
   if (!(isEquality && TrueVal == ConstVal) &&
       !(isNonEquality && FalseVal == ConstVal))
     return SDValue();
-
   SDValue SelectLHS = (isEquality && TrueVal == ConstVal) ? ArgVal : TrueVal;
   SDValue SelectRHS =
       (isNonEquality && FalseVal == ConstVal) ? ArgVal : FalseVal;
@@ -17073,48 +17069,6 @@ SDValue SITargetLowering::foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI,
                          SelectLHS, SelectRHS);
 }
 
-// Try to convert vXiY into vZi32 with X * Y = Z * 32
-SDValue SITargetLowering::castTypeSelect(SDNode *N, DAGCombinerInfo &DCI,
-                                         SDValue Cond, SDValue TrueVal,
-                                         SDValue FalseVal) const {
-  EVT ResultVT = N->getValueType(0);
-  if (ResultVT.isSimple() || !ResultVT.isVector() ||
-      !ResultVT.isPow2VectorType())
-    return SDValue();
-
-  EVT EltVT = ResultVT.getVectorElementType();
-  unsigned EltBitSize = EltVT.getSizeInBits();
-  if (!EltVT.isInteger() || ResultVT.getVectorElementCount().isScalar())
-    return SDValue();
-
-  unsigned NewNumElts = ResultVT.getVectorNumElements() / (32 / EltBitSize);
-
-  if (NewNumElts * 32 != EltBitSize * ResultVT.getVectorNumElements())
-    return SDValue();
-
-  EVT NewVT = EVT::getVectorVT(*DCI.DAG.getContext(), MVT::i32, NewNumElts);
-  SDValue NewTrue =
-      DCI.DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
-  SDValue NewFalse =
-      DCI.DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
-  SDValue NewSelect =
-      DCI.DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
-  return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
-}
-
-SDValue SITargetLowering::performSelectCombine(SDNode *N,
-                                               DAGCombinerInfo &DCI) const {
-
-  SDValue Cond = N->getOperand(0);
-  SDValue TrueVal = N->getOperand(1);
-  SDValue FalseVal = N->getOperand(2);
-
-  if (SDValue Res = foldShareConstSelect(N, DCI, Cond, TrueVal, FalseVal))
-    return Res;
-
-  return castTypeSelect(N, DCI, Cond, TrueVal, FalseVal);
-}
-
 SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
                                             DAGCombinerInfo &DCI) const {
   switch (N->getOpcode()) {
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index f47068fb72ecb..f42d8ec7e35ff 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -227,10 +227,6 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   SDValue performExtractVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performInsertVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   SDValue performFPRoundCombine(SDNode *N, DAGCombinerInfo &DCI) const;
-  SDValue foldShareConstSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue Cond,
-                               SDValue TrueVal, SDValue FalseVal) const;
-  SDValue castTypeSelect(SDNode *N, DAGCombinerInfo &DCI, SDValue Cond,
-                         SDValue TrueVal, SDValue FalseVal) const;
   SDValue performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const;
 
   SDValue reassociateScalarOps(SDNode *N, SelectionDAG &DAG) const;
diff --git a/llvm/test/CodeGen/AMDGPU/select-vectors.ll b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
index 5e52b2fca32c8..69c4b41230e97 100644
--- a/llvm/test/CodeGen/AMDGPU/select-vectors.ll
+++ b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
@@ -463,6 +463,47 @@ define amdgpu_kernel void @v_select_v4f16(ptr addrspace(1) %out, ptr addrspace(1
   ret void
 }
 
+; GCN-LABEL: {{^}}v_select_v16i4:
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define amdgpu_kernel void @v_select_v16i4(ptr addrspace(1) %out, ptr addrspace(1) %a.ptr, ptr addrspace(4) %b.ptr, i32 %c) #0 {
+  %a = load <16 x i4>, ptr addrspace(1) %a.ptr, align 8
+  %b = load <16 x i4>, ptr addrspace(4) %b.ptr, align 8
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, <16 x i4> %a, <16 x i4> %b
+  store <16 x i4> %select, ptr addrspace(1) %out, align 8
+  ret void
+}
+
+; GCN-LABEL: {{^}}v_select_v32i2:
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define amdgpu_kernel void @v_select_v32i2(ptr addrspace(1) %out, ptr addrspace(1) %a.ptr, ptr addrspace(4) %b.ptr, i32 %c) #0 {
+  %a = load <32 x i2>, ptr addrspace(1) %a.ptr, align 8
+  %b = load <32 x i2>, ptr addrspace(4) %b.ptr, align 8
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, <32 x i2> %a, <32 x i2> %b
+  store <32 x i2> %select, ptr addrspace(1) %out, align 8
+  ret void
+}
+
+; GCN-LABEL: {{^}}v_select_v64i2:
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define amdgpu_kernel void @v_select_v64i2(ptr addrspace(1) %out, ptr addrspace(1) %a.ptr, ptr addrspace(4) %b.ptr, i32 %c) #0 {
+  %a = load <64 x i2>, ptr addrspace(1) %a.ptr, align 16
+  %b = load <64 x i2>, ptr addrspace(4) %b.ptr, align 16
+  %cmp = icmp eq i32 %c, 0
+  %select = select i1 %cmp, <64 x i2> %a, <64 x i2> %b
+  store <64 x i2> %select, ptr addrspace(1) %out, align 16
+  ret void
+}
+
 ; Function Attrs: nounwind readnone
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 

>From 336769f2b78bc1886faaef489fc55f53224889e3 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Sun, 25 Jan 2026 12:32:31 +0800
Subject: [PATCH 11/19] revert SISELLOWERING

---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index c1c93cc1ce3c5..07a503c8973a7 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17022,18 +17022,22 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
   // Check if condition is a comparison.
   if (Cond.getOpcode() != ISD::SETCC)
     return SDValue();
+
   SDValue LHS = Cond.getOperand(0);
   SDValue RHS = Cond.getOperand(1);
   ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
+
   bool isFloatingPoint = LHS.getValueType().isFloatingPoint();
   bool isInteger = LHS.getValueType().isInteger();
   // Handle simple floating-point and integer types only.
   if (!isFloatingPoint && !isInteger)
     return SDValue();
+
   bool isEquality = CC == (isFloatingPoint ? ISD::SETOEQ : ISD::SETEQ);
   bool isNonEquality = CC == (isFloatingPoint ? ISD::SETONE : ISD::SETNE);
   if (!isEquality && !isNonEquality)
     return SDValue();
+
   SDValue ArgVal, ConstVal;
   if ((isFloatingPoint && isa<ConstantFPSDNode>(RHS)) ||
       (isInteger && isa<ConstantSDNode>(RHS))) {
@@ -17046,6 +17050,7 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
   } else {
     return SDValue();
   }
+
   // Skip optimization for inlinable immediates.
   if (isFloatingPoint) {
     const APFloat &Val = cast<ConstantFPSDNode>(ConstVal)->getValueAPF();
@@ -17056,12 +17061,14 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
             cast<ConstantSDNode>(ConstVal)->getSExtValue()))
       return SDValue();
   }
+
   // For equality and non-equality comparisons, patterns:
   // select (setcc x, const), const, y -> select (setcc x, const), x, y
   // select (setccinv x, const), y, const -> select (setccinv x, const), y, x
   if (!(isEquality && TrueVal == ConstVal) &&
       !(isNonEquality && FalseVal == ConstVal))
     return SDValue();
+
   SDValue SelectLHS = (isEquality && TrueVal == ConstVal) ? ArgVal : TrueVal;
   SDValue SelectRHS =
       (isNonEquality && FalseVal == ConstVal) ? ArgVal : FalseVal;

>From 87cd0870c254f126b75f72a1a1ad4abed5b4489a Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Sun, 25 Jan 2026 12:33:24 +0800
Subject: [PATCH 12/19] revert SIISelLowering.cpp

---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 07a503c8973a7..e9c46e53affe4 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -17029,6 +17029,7 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
 
   bool isFloatingPoint = LHS.getValueType().isFloatingPoint();
   bool isInteger = LHS.getValueType().isInteger();
+
   // Handle simple floating-point and integer types only.
   if (!isFloatingPoint && !isInteger)
     return SDValue();

>From 849d5944abf7f18242b3b0b871a6298443f7d097 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Sun, 25 Jan 2026 13:41:57 +0800
Subject: [PATCH 13/19] fix AArch64 test failure

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  9 ++++++---
 llvm/test/CodeGen/AMDGPU/select-vectors.ll    | 15 ---------------
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index bb21e7a8deaac..6e82dc0eac297 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6975,11 +6975,14 @@ static SDValue combineSelectAsExtAnd(SDValue Cond, SDValue T, SDValue F,
 // Try to convert vXiY into vZi32 with X * Y = Z * 32
 // This prevent promotion of integer vectors like v32i4 to v32i16
 // which can create extra operations on type casting.
-static SDValue castTypeSelect(SDNode *N, SelectionDAG &DAG, SDValue Cond,
+static SDValue castTypeSelect(SDNode *N, SelectionDAG &DAG,
+                              const TargetLowering &TLI, SDValue Cond,
                               SDValue TrueVal, SDValue FalseVal) {
   EVT ResultVT = N->getValueType(0);
   if (ResultVT.isSimple() || !ResultVT.isVector() ||
-      !ResultVT.isPow2VectorType())
+      !ResultVT.isPow2VectorType() ||
+      TLI.getTypeAction(*DAG.getContext(), ResultVT) !=
+          TargetLowering::TypePromoteInteger)
     return SDValue();
 
   EVT EltVT = ResultVT.getVectorElementType();
@@ -12790,7 +12793,7 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
   if (SDValue R = combineSelectAsExtAnd(N0, N1, N2, DL, DAG))
     return R;
 
-  if (SDValue R = castTypeSelect(N, DAG, N0, N1, N2))
+  if (SDValue R = castTypeSelect(N, DAG, TLI, N0, N1, N2))
     return R;
 
   return SDValue();
diff --git a/llvm/test/CodeGen/AMDGPU/select-vectors.ll b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
index 69c4b41230e97..d76fa51376bb4 100644
--- a/llvm/test/CodeGen/AMDGPU/select-vectors.ll
+++ b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
@@ -489,21 +489,6 @@ define amdgpu_kernel void @v_select_v32i2(ptr addrspace(1) %out, ptr addrspace(1
   ret void
 }
 
-; GCN-LABEL: {{^}}v_select_v64i2:
-; GCN: v_cndmask_b32_e32
-; GCN: v_cndmask_b32_e32
-; GCN: v_cndmask_b32_e32
-; GCN: v_cndmask_b32_e32
-; GCN-NOT: cndmask
-define amdgpu_kernel void @v_select_v64i2(ptr addrspace(1) %out, ptr addrspace(1) %a.ptr, ptr addrspace(4) %b.ptr, i32 %c) #0 {
-  %a = load <64 x i2>, ptr addrspace(1) %a.ptr, align 16
-  %b = load <64 x i2>, ptr addrspace(4) %b.ptr, align 16
-  %cmp = icmp eq i32 %c, 0
-  %select = select i1 %cmp, <64 x i2> %a, <64 x i2> %b
-  store <64 x i2> %select, ptr addrspace(1) %out, align 16
-  ret void
-}
-
 ; Function Attrs: nounwind readnone
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 

>From 4107553807416102b40210b5972b7d6c87c2aab2 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 27 Jan 2026 17:58:31 +0800
Subject: [PATCH 14/19] try to widden before convert type

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 35 ++++++++++++++++---
 llvm/test/CodeGen/AMDGPU/select-vectors.ll    | 21 +++++++++++
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 298a75a6a9227..27c4b1703d92c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6976,12 +6976,36 @@ static SDValue combineSelectAsExtAnd(SDValue Cond, SDValue T, SDValue F,
   return DAG.getNode(ISD::AND, DL, OpVT, CondMask, T.getOperand(0));
 }
 
+// Widden int vector is not power of 2 in length.
+static SDValue widdenIntVectorSelect(SDNode *N, SelectionDAG &DAG,
+                                     const TargetLowering &TLI, SDValue Cond,
+                                     SDValue TrueVal, SDValue FalseVal) {
+  EVT ResultVT = N->getValueType(0);
+  if (ResultVT.isSimple() || !ResultVT.isVector() ||
+      ResultVT.isPow2VectorType() ||
+      TLI.getTypeAction(*DAG.getContext(), ResultVT) !=
+          TargetLowering::TypeWidenVector)
+    return SDValue();
+
+  EVT EltVT = ResultVT.getVectorElementType();
+  if (!EltVT.isInteger() || ResultVT.getVectorElementCount().isScalar())
+    return SDValue();
+
+  SDValue WiddenTrue = DAG.WidenVector(TrueVal, SDLoc(TrueVal));
+  SDValue WiddenFalse = DAG.WidenVector(FalseVal, SDLoc(FalseVal));
+
+  EVT WiddenVT = WiddenTrue.getValueType();
+  SDValue WiddenSelect = DAG.getNode(ISD::SELECT, SDLoc(N), WiddenVT, Cond,
+                                     WiddenTrue, WiddenFalse);
+  return DAG.getExtractSubvector(SDLoc(N), ResultVT, WiddenSelect, 0);
+}
+
 // Try to convert vXiY into vZi32 with X * Y = Z * 32
 // This prevent promotion of integer vectors like v32i4 to v32i16
 // which can create extra operations on type casting.
-static SDValue castTypeSelect(SDNode *N, SelectionDAG &DAG,
-                              const TargetLowering &TLI, SDValue Cond,
-                              SDValue TrueVal, SDValue FalseVal) {
+static SDValue castIntVectorSelect(SDNode *N, SelectionDAG &DAG,
+                                   const TargetLowering &TLI, SDValue Cond,
+                                   SDValue TrueVal, SDValue FalseVal) {
   EVT ResultVT = N->getValueType(0);
   if (ResultVT.isSimple() || !ResultVT.isVector() ||
       !ResultVT.isPow2VectorType() ||
@@ -12820,7 +12844,10 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
   if (SDValue R = combineSelectAsExtAnd(N0, N1, N2, DL, DAG))
     return R;
 
-  if (SDValue R = castTypeSelect(N, DAG, TLI, N0, N1, N2))
+  if (SDValue R = widdenIntVectorSelect(N, DAG, TLI, N0, N1, N2))
+    return R;
+
+  if (SDValue R = castIntVectorSelect(N, DAG, TLI, N0, N1, N2))
     return R;
 
   return SDValue();
diff --git a/llvm/test/CodeGen/AMDGPU/select-vectors.ll b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
index d76fa51376bb4..0a433e632444d 100644
--- a/llvm/test/CodeGen/AMDGPU/select-vectors.ll
+++ b/llvm/test/CodeGen/AMDGPU/select-vectors.ll
@@ -489,6 +489,27 @@ define amdgpu_kernel void @v_select_v32i2(ptr addrspace(1) %out, ptr addrspace(1
   ret void
 }
 
+; GCN-LABEL: {{^}}v_select_v15i4:
+; GCN: v_cndmask_b32_e32
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define void @v_select_v15i4(i1 %cond, ptr addrspace(1) %x, ptr addrspace(3) %y) {
+  %v = load <15 x i4>, ptr addrspace(1) %x, align 16
+  %vMasked = select i1 %cond, <15 x i4> %v, <15 x i4> zeroinitializer
+  store <15 x i4> %vMasked, ptr addrspace(3) %y, align 16
+  ret void
+}
+
+; GCN-LABEL: {{^}}v_select_v7i4:
+; GCN: v_cndmask_b32_e32
+; GCN-NOT: cndmask
+define void @v_select_v7i4(i1 %cond, ptr addrspace(1) %x, ptr addrspace(3) %y) {
+  %v = load <7 x i4>, ptr addrspace(1) %x, align 16
+  %vMasked = select i1 %cond, <7 x i4> %v, <7 x i4> zeroinitializer
+  store <7 x i4> %vMasked, ptr addrspace(3) %y, align 16
+  ret void
+}
+
 ; Function Attrs: nounwind readnone
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 

>From 92561833c55e3f1f9ed2911cd683375eda141bce Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 29 Jan 2026 15:09:00 +0800
Subject: [PATCH 15/19] fix comments

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 27c4b1703d92c..5813c28753d44 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7021,12 +7021,11 @@ static SDValue castIntVectorSelect(SDNode *N, SelectionDAG &DAG,
   if (NewVT == EVT())
     return SDValue();
 
-  SDValue NewTrue = DAG.getNode(ISD::BITCAST, SDLoc(TrueVal), NewVT, TrueVal);
-  SDValue NewFalse =
-      DAG.getNode(ISD::BITCAST, SDLoc(FalseVal), NewVT, FalseVal);
+  SDValue NewTrue = DAG.getBitcast(NewVT, TrueVal);
+  SDValue NewFalse = DAG.getBitcast(NewVT, FalseVal);
   SDValue NewSelect =
       DAG.getNode(ISD::SELECT, SDLoc(N), NewVT, Cond, NewTrue, NewFalse);
-  return DAG.getNode(ISD::BITCAST, SDLoc(N), ResultVT, NewSelect);
+  return DAG.getBitcast(ResultVT, NewSelect);
 }
 
 /// This contains all DAGCombine rules which reduce two values combined by

>From a65e2daf9c4c644bc0503f65532b26e63b4c7b75 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 3 Feb 2026 14:58:58 +0800
Subject: [PATCH 16/19] fix comments

---
 llvm/include/llvm/CodeGen/ValueTypes.h | 18 +-----------------
 llvm/lib/CodeGen/ValueTypes.cpp        | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/ValueTypes.h b/llvm/include/llvm/CodeGen/ValueTypes.h
index 3736c89aaf4c7..8620e37632ce3 100644
--- a/llvm/include/llvm/CodeGen/ValueTypes.h
+++ b/llvm/include/llvm/CodeGen/ValueTypes.h
@@ -454,23 +454,7 @@ namespace llvm {
     /// integer vector, or if the total bits are not evenly divisible by the new
     /// element width.
     EVT getIntegerVectorWithElementWidth(LLVMContext &Context,
-                                         unsigned NewEltWidth) const {
-      if (!isVector() || !isInteger())
-        return EVT();
-
-      unsigned TotalBits = getVectorMinNumElements() * getScalarSizeInBits();
-      if (TotalBits % NewEltWidth != 0)
-        return EVT();
-
-      unsigned NewNumElements = TotalBits / NewEltWidth;
-      EVT NewEltVT = EVT::getIntegerVT(Context, NewEltWidth);
-
-      // Preserve scalability
-      ElementCount EC = getVectorElementCount();
-      ElementCount NewEC = ElementCount::get(NewNumElements, EC.isScalable());
-
-      return EVT::getVectorVT(Context, NewEltVT, NewEC);
-    }
+                                         unsigned NewEltWidth) const;
 
     // Return a VT for a vector type with the same element type but
     // half the number of elements. The type returned may be an
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 0743c92c5b95b..a07689376b143 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -59,6 +59,25 @@ EVT EVT::getExtendedVectorVT(LLVMContext &Context, EVT VT, ElementCount EC) {
   return ResultVT;
 }
 
+EVT EVT::getIntegerVectorWithElementWidth(LLVMContext &Context,
+                                          unsigned NewEltWidth) const {
+  if (!isVector() || !isInteger())
+    return EVT();
+
+  unsigned TotalBits = getVectorMinNumElements() * getScalarSizeInBits();
+  if (TotalBits % NewEltWidth != 0)
+    return EVT();
+
+  unsigned NewNumElements = TotalBits / NewEltWidth;
+  EVT NewEltVT = EVT::getIntegerVT(Context, NewEltWidth);
+
+  // Preserve scalability
+  ElementCount EC = getVectorElementCount();
+  ElementCount NewEC = ElementCount::get(NewNumElements, EC.isScalable());
+
+  return EVT::getVectorVT(Context, NewEltVT, NewEC);
+}
+
 bool EVT::isExtendedFloatingPoint() const {
   assert(isExtended() && "Type is not extended!");
   return LLVMTy->isFPOrFPVectorTy();

>From 426e7fbf80548915db812b8d3d13a783aef6f546 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Fri, 27 Feb 2026 16:39:55 +0800
Subject: [PATCH 17/19] Remove hard code 32 bit, upward searching leagal VT

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 23 +++++++++++++------
 llvm/lib/CodeGen/ValueTypes.cpp               |  5 +++-
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 5085b62ecd005..319043bcfa582 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7026,19 +7026,28 @@ static SDValue castIntVectorSelect(SDNode *N, SelectionDAG &DAG,
                                    const TargetLowering &TLI, SDValue Cond,
                                    SDValue TrueVal, SDValue FalseVal) {
   EVT ResultVT = N->getValueType(0);
-  if (ResultVT.isSimple() || !ResultVT.isVector() ||
-      !ResultVT.isPow2VectorType() ||
-      TLI.getTypeAction(*DAG.getContext(), ResultVT) !=
-          TargetLowering::TypePromoteInteger)
+  if (!ResultVT.isVector() || TLI.getTypeAction(*DAG.getContext(), ResultVT) ==
+                                  TargetLowering::TypeLegal)
     return SDValue();
 
   EVT EltVT = ResultVT.getVectorElementType();
   if (!EltVT.isInteger() || ResultVT.getVectorElementCount().isScalar())
     return SDValue();
 
-  EVT NewVT = ResultVT.getIntegerVectorWithElementWidth(*DAG.getContext(), 32);
-  if (NewVT == EVT())
-    return SDValue();
+  unsigned NewEltBitSize = EltVT.getSizeInBits() * 2;
+  EVT NewVT = ResultVT.getIntegerVectorWithElementWidth(*DAG.getContext(),
+                                                        NewEltBitSize);
+  while (true) {
+    if (NewVT == EVT())
+      return SDValue();
+    if (TLI.getTypeAction(*DAG.getContext(), NewVT) ==
+        TargetLowering::TypeLegal)
+      break;
+
+    NewEltBitSize *= 2;
+    NewVT = ResultVT.getIntegerVectorWithElementWidth(*DAG.getContext(),
+                                                      NewEltBitSize);
+  }
 
   SDValue NewTrue = DAG.getBitcast(NewVT, TrueVal);
   SDValue NewFalse = DAG.getBitcast(NewVT, FalseVal);
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index a07689376b143..22138c60a000e 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -65,12 +65,15 @@ EVT EVT::getIntegerVectorWithElementWidth(LLVMContext &Context,
     return EVT();
 
   unsigned TotalBits = getVectorMinNumElements() * getScalarSizeInBits();
-  if (TotalBits % NewEltWidth != 0)
+  if (TotalBits % NewEltWidth != 0 || NewEltWidth > TotalBits)
     return EVT();
 
   unsigned NewNumElements = TotalBits / NewEltWidth;
   EVT NewEltVT = EVT::getIntegerVT(Context, NewEltWidth);
 
+  if (NewNumElements == 1)
+    return NewEltVT;
+
   // Preserve scalability
   ElementCount EC = getVectorElementCount();
   ElementCount NewEC = ElementCount::get(NewNumElements, EC.isScalable());

>From f16432e859ccb9d8c2ceff800fcfaa28f32cf138 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Fri, 27 Feb 2026 16:42:41 +0800
Subject: [PATCH 18/19] update comments

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 319043bcfa582..a327ed5e70253 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7019,7 +7019,10 @@ static SDValue widdenIntVectorSelect(SDNode *N, SelectionDAG &DAG,
   return DAG.getExtractSubvector(SDLoc(N), ResultVT, WiddenSelect, 0);
 }
 
-// Try to convert vXiY into vZi32 with X * Y = Z * 32
+// Try to convert vXiY into vPiQ with:
+// 1. vXiY is not legal type
+// 2. vPiQ is legal type
+// 3. X * Y = P * Q
 // This prevent promotion of integer vectors like v32i4 to v32i16
 // which can create extra operations on type casting.
 static SDValue castIntVectorSelect(SDNode *N, SelectionDAG &DAG,

>From 2fd8996592cb048a238026d63f0d0f4aafe3f2c5 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Sat, 28 Feb 2026 14:27:54 +0800
Subject: [PATCH 19/19] add switch function

---
 llvm/include/llvm/CodeGen/TargetLowering.h    | 9 +++++++++
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 6 ++++--
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h   | 2 ++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 4b60c3f905120..b1035912f0242 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5899,6 +5899,15 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
     return true;
   }
 
+  // Return ture if should transform:
+  //    `t0:vXiY = select i1, t1, t2`
+  // To:
+  //    `t3:vPiQ = bitcast t1`
+  //    `t4:vPiQ = bitcast t2`
+  //    `t5:vPiQ = select i1, t3, t4`
+  //    `t0:vXiY = bitcast t5`
+  virtual bool shouldCastIntVectorSelect(EVT VT) const { return false; }
+
   // Expand vector operation by dividing it into smaller length operations and
   // joining their results. SDValue() is returned when expansion did not happen.
   SDValue expandVectorNaryOpBySplitting(SDNode *Node, SelectionDAG &DAG) const;
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index a327ed5e70253..61d8f25e3591e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7029,8 +7029,10 @@ static SDValue castIntVectorSelect(SDNode *N, SelectionDAG &DAG,
                                    const TargetLowering &TLI, SDValue Cond,
                                    SDValue TrueVal, SDValue FalseVal) {
   EVT ResultVT = N->getValueType(0);
-  if (!ResultVT.isVector() || TLI.getTypeAction(*DAG.getContext(), ResultVT) ==
-                                  TargetLowering::TypeLegal)
+  if (!ResultVT.isVector() ||
+      TLI.getTypeAction(*DAG.getContext(), ResultVT) ==
+          TargetLowering::TypeLegal ||
+      !TLI.shouldCastIntVectorSelect(ResultVT))
     return SDValue();
 
   EVT EltVT = ResultVT.getVectorElementType();
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
index b4d1cd921e601..0d0c234e689cc 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
@@ -398,6 +398,8 @@ class AMDGPUTargetLowering : public TargetLowering {
     return MVT::i32;
   }
 
+  bool shouldCastIntVectorSelect(EVT VT) const override { return true; }
+
   bool hasMultipleConditionRegisters(EVT VT) const override {
     // FIXME: This is only partially true. If we have to do vector compares, any
     // SGPR pair can be a condition register. If we have a uniform condition, we



More information about the llvm-commits mailing list