[llvm] [AMDGPU][X86][DAG] Avoid duplicate BinOp result from narrowing insert-extract sub-vector (PR #201056)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 02:51:39 PDT 2026


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

>From 8a3d5809ebc71ec3bff13d7234e8fa8fc97e576b Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 2 Jun 2026 16:17:22 +0800
Subject: [PATCH 1/7] use target specific hook to block narrowing
 insert-extract subvector

---
 llvm/include/llvm/CodeGen/TargetLowering.h    |  7 ++
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  2 +
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 15 +++-
 llvm/lib/Target/AMDGPU/SIISelLowering.h       |  3 +-
 llvm/test/CodeGen/AMDGPU/fmax_legacy.f16.ll   |  2 +-
 llvm/test/CodeGen/AMDGPU/fmin_legacy.f16.ll   |  2 +-
 llvm/test/CodeGen/AMDGPU/llvm.maximum.f16.ll  |  8 +-
 llvm/test/CodeGen/AMDGPU/llvm.minimum.f16.ll  |  8 +-
 llvm/test/CodeGen/AMDGPU/maximumnum.ll        | 84 +++++++++----------
 llvm/test/CodeGen/AMDGPU/minimumnum.ll        | 84 +++++++++----------
 llvm/test/CodeGen/AMDGPU/saddsat.ll           |  2 +-
 llvm/test/CodeGen/AMDGPU/ssubsat.ll           |  2 +-
 llvm/test/CodeGen/AMDGPU/uaddsat.ll           |  2 +-
 llvm/test/CodeGen/AMDGPU/usubsat.ll           |  2 +-
 14 files changed, 121 insertions(+), 102 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 82c47cce0f522..a57fd2ede44ea 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -3527,6 +3527,13 @@ class LLVM_ABI TargetLoweringBase {
     return false;
   }
 
+  /// Return true if it is profitable to narrow a vector binop feeding an
+  /// extract_subvector into a binop of the extracted vector type.
+  virtual bool shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
+                                                unsigned Index) const {
+    return true;
+  }
+
   /// Return true if extraction of a scalar element from the given vector type
   /// at the given index is cheap. For example, if scalar operations occur on
   /// the same register file as vector operations, then an extract element may
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 0c9820fb64de9..c4c12fbf5dde6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27192,6 +27192,8 @@ static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
     return SDValue();
 
   EVT VecVT = BinOp.getValueType();
+  if (!TLI.shouldNarrowExtractedVectorBinOp(VecVT, SubVT, Index))
+    return SDValue();
   SDValue Bop0 = BinOp.getOperand(0), Bop1 = BinOp.getOperand(1);
   if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType())
     return SDValue();
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 86f2479490c29..b735d00be58e7 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -892,7 +892,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
       for (MVT VT : {MVT::v4bf16, MVT::v8bf16, MVT::v16bf16, MVT::v32bf16})
         // Split vector operations.
         setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FCANONICALIZE,
-                            ISD::FNEG, ISD::FABS},
+                            ISD::FNEG, ISD::FABS, ISD::FMAXNUM, ISD::FMINNUM},
                            VT, Custom);
     }
 
@@ -2354,6 +2354,19 @@ bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
   return true;
 }
 
+bool SITargetLowering::shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
+                                                        unsigned Index) const {
+  unsigned ScalarBits = SubVT.getScalarSizeInBits();
+  unsigned OffsetBits = Index * ScalarBits;
+  unsigned SubvectorBits = SubVT.getSizeInBits();
+
+  // If the extracted subvector starts on a dword boundary and has a dword
+  // sized payload, keeping the original wide result is preferable because the
+  // subvector can be referenced directly through subregisters. Otherwise,
+  // narrowing may avoid element extraction or reconstruction.
+  return OffsetBits % 32 != 0 || SubvectorBits % 32 != 0;
+}
+
 bool SITargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                                unsigned Index) const {
   if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT))
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 95ff5bba7cfff..154faefb37ae1 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -399,7 +399,8 @@ class SITargetLowering final : public AMDGPUTargetLowering {
 
   bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
                                         Type *Ty) const override;
-
+  bool shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
+                                        unsigned Index) const override;
   bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                unsigned Index) const override;
   bool isExtractVecEltCheap(EVT VT, unsigned Index) const override;
diff --git a/llvm/test/CodeGen/AMDGPU/fmax_legacy.f16.ll b/llvm/test/CodeGen/AMDGPU/fmax_legacy.f16.ll
index f980288865b8b..8a0cb0d6de739 100644
--- a/llvm/test/CodeGen/AMDGPU/fmax_legacy.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fmax_legacy.f16.ll
@@ -289,8 +289,8 @@ define <3 x half> @test_fmax_legacy_ugt_v3f16_fast(<3 x half> %a, <3 x half> %b)
 ; GFX9-LABEL: test_fmax_legacy_ugt_v3f16_fast:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; VI-LABEL: test_fmax_legacy_ugt_v3f16_fast:
diff --git a/llvm/test/CodeGen/AMDGPU/fmin_legacy.f16.ll b/llvm/test/CodeGen/AMDGPU/fmin_legacy.f16.ll
index 41b7b7fe6b21a..04d9bfd4e9192 100644
--- a/llvm/test/CodeGen/AMDGPU/fmin_legacy.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fmin_legacy.f16.ll
@@ -290,8 +290,8 @@ define <3 x half> @test_fmin_legacy_ule_v3f16_fast(<3 x half> %a, <3 x half> %b)
 ; GFX9-LABEL: test_fmin_legacy_ule_v3f16_fast:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; VI-LABEL: test_fmin_legacy_ule_v3f16_fast:
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.maximum.f16.ll b/llvm/test/CodeGen/AMDGPU/llvm.maximum.f16.ll
index a60741905bdbd..ab5605d6d89db 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.maximum.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.maximum.f16.ll
@@ -1310,8 +1310,8 @@ define <3 x half> @v_maximum_v3f16(<3 x half> %src0, <3 x half> %src1) {
 ; GFX950-LABEL: v_maximum_v3f16:
 ; GFX950:       ; %bb.0:
 ; GFX950-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX950-NEXT:    v_pk_maximum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    v_pk_maximum3_f16 v0, v0, v2, v2
+; GFX950-NEXT:    v_pk_maximum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximum_v3f16:
@@ -1419,8 +1419,8 @@ define <3 x half> @v_maximum_v3f16__nnan(<3 x half> %src0, <3 x half> %src1) {
 ; GFX9-LABEL: v_maximum_v3f16__nnan:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximum_v3f16__nnan:
@@ -1524,8 +1524,8 @@ define <3 x half> @v_maximum_v3f16__nsz(<3 x half> %src0, <3 x half> %src1) {
 ; GFX950-LABEL: v_maximum_v3f16__nsz:
 ; GFX950:       ; %bb.0:
 ; GFX950-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX950-NEXT:    v_pk_maximum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    v_pk_maximum3_f16 v0, v0, v2, v2
+; GFX950-NEXT:    v_pk_maximum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximum_v3f16__nsz:
@@ -1633,8 +1633,8 @@ define <3 x half> @v_maximum_v3f16__nnan_nsz(<3 x half> %src0, <3 x half> %src1)
 ; GFX9-LABEL: v_maximum_v3f16__nnan_nsz:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximum_v3f16__nnan_nsz:
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.minimum.f16.ll b/llvm/test/CodeGen/AMDGPU/llvm.minimum.f16.ll
index cd01dfc2d3dc8..a262181921f15 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.minimum.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.minimum.f16.ll
@@ -1092,8 +1092,8 @@ define <3 x half> @v_minimum_v3f16(<3 x half> %src0, <3 x half> %src1) {
 ; GFX950-LABEL: v_minimum_v3f16:
 ; GFX950:       ; %bb.0:
 ; GFX950-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX950-NEXT:    v_pk_minimum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    v_pk_minimum3_f16 v0, v0, v2, v2
+; GFX950-NEXT:    v_pk_minimum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimum_v3f16:
@@ -1180,8 +1180,8 @@ define <3 x half> @v_minimum_v3f16__nnan(<3 x half> %src0, <3 x half> %src1) {
 ; GFX9-LABEL: v_minimum_v3f16__nnan:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimum_v3f16__nnan:
@@ -1257,8 +1257,8 @@ define <3 x half> @v_minimum_v3f16__nsz(<3 x half> %src0, <3 x half> %src1) {
 ; GFX950-LABEL: v_minimum_v3f16__nsz:
 ; GFX950:       ; %bb.0:
 ; GFX950-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX950-NEXT:    v_pk_minimum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    v_pk_minimum3_f16 v0, v0, v2, v2
+; GFX950-NEXT:    v_pk_minimum3_f16 v1, v1, v3, v3
 ; GFX950-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimum_v3f16__nsz:
@@ -1345,8 +1345,8 @@ define <3 x half> @v_minimum_v3f16__nnan_nsz(<3 x half> %src0, <3 x half> %src1)
 ; GFX9-LABEL: v_minimum_v3f16__nnan_nsz:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimum_v3f16__nnan_nsz:
diff --git a/llvm/test/CodeGen/AMDGPU/maximumnum.ll b/llvm/test/CodeGen/AMDGPU/maximumnum.ll
index c0f80363e6850..4ba8ff42390ac 100644
--- a/llvm/test/CodeGen/AMDGPU/maximumnum.ll
+++ b/llvm/test/CodeGen/AMDGPU/maximumnum.ll
@@ -4301,16 +4301,16 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_maximumnum_v3f16:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
+; GFX900-SDAG-LABEL: v_maximumnum_v3f16:
+; GFX900-SDAG:       ; %bb.0:
+; GFX900-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v2, v3, v3
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v1, v1, v2
+; GFX900-SDAG-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX900-GISEL-LABEL: v_maximumnum_v3f16:
 ; GFX900-GISEL:       ; %bb.0:
@@ -4323,6 +4323,18 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX900-GISEL-NEXT:    v_pk_max_f16 v1, v1, v2
 ; GFX900-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
+; GFX950-SDAG-LABEL: v_maximumnum_v3f16:
+; GFX950-SDAG:       ; %bb.0:
+; GFX950-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v2, v3, v3
+; GFX950-SDAG-NEXT:    s_nop 0
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v1, v1, v2
+; GFX950-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
 ; GFX950-GISEL-LABEL: v_maximumnum_v3f16:
 ; GFX950-GISEL:       ; %bb.0:
 ; GFX950-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
@@ -4338,9 +4350,9 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX10-SDAG-LABEL: v_maximumnum_v3f16:
 ; GFX10-SDAG:       ; %bb.0:
 ; GFX10-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX10-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v1, v1, v3
@@ -4360,11 +4372,11 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX11-SDAG-LABEL: v_maximumnum_v3f16:
 ; GFX11-SDAG:       ; %bb.0:
 ; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX11-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
-; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v1, v1, v3
 ; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4384,11 +4396,11 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX1170-SDAG-LABEL: v_maximumnum_v3f16:
 ; GFX1170-SDAG:       ; %bb.0:
 ; GFX1170-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v2, v2, v2
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v0
+; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v1
-; GFX1170-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX1170-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v2
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v3
 ; GFX1170-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4412,11 +4424,11 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX12-SDAG-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-SDAG-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-SDAG-NEXT:    s_wait_kmcnt 0x0
-; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v2, v2, v2
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v0
+; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v1
-; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v2
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v3
 ; GFX12-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4501,19 +4513,12 @@ define <3 x half> @v_maximumnum_v3f16_nnan(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_maximumnum_v3f16_nnan:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_maximumnum_v3f16_nnan:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_pk_max_f16 v0, v0, v2
-; GFX9-GISEL-NEXT:    v_pk_max_f16 v1, v1, v3
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_maximumnum_v3f16_nnan:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximumnum_v3f16_nnan:
 ; GFX10:       ; %bb.0:
@@ -10079,19 +10084,12 @@ define <3 x half> @v_maximumnum_v3f16_nnan_no_ieee(<3 x half> %x, <3 x half> %y)
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_maximumnum_v3f16_nnan_no_ieee:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_maximumnum_v3f16_nnan_no_ieee:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_pk_max_f16 v0, v0, v2
-; GFX9-GISEL-NEXT:    v_pk_max_f16 v1, v1, v3
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_maximumnum_v3f16_nnan_no_ieee:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_max_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_max_f16 v1, v1, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_maximumnum_v3f16_nnan_no_ieee:
 ; GFX10:       ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/minimumnum.ll b/llvm/test/CodeGen/AMDGPU/minimumnum.ll
index 18ea5e2dd0e6c..187e8b26d4394 100644
--- a/llvm/test/CodeGen/AMDGPU/minimumnum.ll
+++ b/llvm/test/CodeGen/AMDGPU/minimumnum.ll
@@ -4091,16 +4091,16 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_minimumnum_v3f16:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
+; GFX900-SDAG-LABEL: v_minimumnum_v3f16:
+; GFX900-SDAG:       ; %bb.0:
+; GFX900-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX900-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v2, v3, v3
+; GFX900-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
+; GFX900-SDAG-NEXT:    v_pk_min_f16 v1, v1, v2
+; GFX900-SDAG-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX900-GISEL-LABEL: v_minimumnum_v3f16:
 ; GFX900-GISEL:       ; %bb.0:
@@ -4113,6 +4113,18 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX900-GISEL-NEXT:    v_pk_min_f16 v1, v1, v2
 ; GFX900-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
+; GFX950-SDAG-LABEL: v_minimumnum_v3f16:
+; GFX950-SDAG:       ; %bb.0:
+; GFX950-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
+; GFX950-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX950-SDAG-NEXT:    v_pk_max_f16 v2, v3, v3
+; GFX950-SDAG-NEXT:    s_nop 0
+; GFX950-SDAG-NEXT:    v_pk_min_f16 v1, v1, v2
+; GFX950-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
 ; GFX950-GISEL-LABEL: v_minimumnum_v3f16:
 ; GFX950-GISEL:       ; %bb.0:
 ; GFX950-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
@@ -4128,9 +4140,9 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX10-SDAG-LABEL: v_minimumnum_v3f16:
 ; GFX10-SDAG:       ; %bb.0:
 ; GFX10-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX10-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX10-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
 ; GFX10-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
 ; GFX10-SDAG-NEXT:    v_pk_min_f16 v1, v1, v3
@@ -4150,11 +4162,11 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX11-SDAG-LABEL: v_minimumnum_v3f16:
 ; GFX11-SDAG:       ; %bb.0:
 ; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v2, v2, v2
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX11-SDAG-NEXT:    v_pk_max_f16 v3, v3, v3
 ; GFX11-SDAG-NEXT:    v_pk_max_f16 v1, v1, v1
-; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX11-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
 ; GFX11-SDAG-NEXT:    v_pk_min_f16 v1, v1, v3
 ; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4174,11 +4186,11 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX1170-SDAG-LABEL: v_minimumnum_v3f16:
 ; GFX1170-SDAG:       ; %bb.0:
 ; GFX1170-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v2, v2, v2
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v0
+; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX1170-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v1
-; GFX1170-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX1170-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX1170-SDAG-NEXT:    v_pk_min_num_f16 v0, v0, v2
 ; GFX1170-SDAG-NEXT:    v_pk_min_num_f16 v1, v1, v3
 ; GFX1170-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4202,11 +4214,11 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX12-SDAG-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-SDAG-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-SDAG-NEXT:    s_wait_kmcnt 0x0
-; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v2, v2, v2
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v0, v0, v0
+; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v3, v3, v3
 ; GFX12-SDAG-NEXT:    v_pk_max_num_f16 v1, v1, v1
-; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
 ; GFX12-SDAG-NEXT:    v_pk_min_num_f16 v0, v0, v2
 ; GFX12-SDAG-NEXT:    v_pk_min_num_f16 v1, v1, v3
 ; GFX12-SDAG-NEXT:    s_setpc_b64 s[30:31]
@@ -4291,19 +4303,12 @@ define <3 x half> @v_minimumnum_v3f16_nnan(<3 x half> %x, <3 x half> %y) #1 {
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_minimumnum_v3f16_nnan:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_minimumnum_v3f16_nnan:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_pk_min_f16 v0, v0, v2
-; GFX9-GISEL-NEXT:    v_pk_min_f16 v1, v1, v3
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_minimumnum_v3f16_nnan:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimumnum_v3f16_nnan:
 ; GFX10:       ; %bb.0:
@@ -9869,19 +9874,12 @@ define <3 x half> @v_minimumnum_v3f16_nnan_no_ieee(<3 x half> %x, <3 x half> %y)
 ; GFX8-GISEL-NEXT:    v_or_b32_e32 v0, v4, v0
 ; GFX8-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_minimumnum_v3f16_nnan_no_ieee:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v1, v1, v3
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v0, v0, v2
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_minimumnum_v3f16_nnan_no_ieee:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_pk_min_f16 v0, v0, v2
-; GFX9-GISEL-NEXT:    v_pk_min_f16 v1, v1, v3
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_minimumnum_v3f16_nnan_no_ieee:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_min_f16 v0, v0, v2
+; GFX9-NEXT:    v_pk_min_f16 v1, v1, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_minimumnum_v3f16_nnan_no_ieee:
 ; GFX10:       ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/saddsat.ll b/llvm/test/CodeGen/AMDGPU/saddsat.ll
index 5d5f3be9ce9fd..b8e44f26b3a0f 100644
--- a/llvm/test/CodeGen/AMDGPU/saddsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/saddsat.ll
@@ -268,8 +268,8 @@ define <3 x i16> @v_saddsat_v3i16(<3 x i16> %lhs, <3 x i16> %rhs) {
 ; GFX9-LABEL: v_saddsat_v3i16:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_add_i16 v1, v1, v3 clamp
 ; GFX9-NEXT:    v_pk_add_i16 v0, v0, v2 clamp
+; GFX9-NEXT:    v_pk_add_i16 v1, v1, v3 clamp
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10PLUS-LABEL: v_saddsat_v3i16:
diff --git a/llvm/test/CodeGen/AMDGPU/ssubsat.ll b/llvm/test/CodeGen/AMDGPU/ssubsat.ll
index d65cb0a3432f2..7a9a340c3f40b 100644
--- a/llvm/test/CodeGen/AMDGPU/ssubsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/ssubsat.ll
@@ -268,8 +268,8 @@ define <3 x i16> @v_ssubsat_v3i16(<3 x i16> %lhs, <3 x i16> %rhs) {
 ; GFX9-LABEL: v_ssubsat_v3i16:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_sub_i16 v1, v1, v3 clamp
 ; GFX9-NEXT:    v_pk_sub_i16 v0, v0, v2 clamp
+; GFX9-NEXT:    v_pk_sub_i16 v1, v1, v3 clamp
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10PLUS-LABEL: v_ssubsat_v3i16:
diff --git a/llvm/test/CodeGen/AMDGPU/uaddsat.ll b/llvm/test/CodeGen/AMDGPU/uaddsat.ll
index 63ab0a3bde0e6..484c69e3c7e00 100644
--- a/llvm/test/CodeGen/AMDGPU/uaddsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/uaddsat.ll
@@ -218,8 +218,8 @@ define <3 x i16> @v_uaddsat_v3i16(<3 x i16> %lhs, <3 x i16> %rhs) {
 ; GFX9-LABEL: v_uaddsat_v3i16:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_add_u16 v1, v1, v3 clamp
 ; GFX9-NEXT:    v_pk_add_u16 v0, v0, v2 clamp
+; GFX9-NEXT:    v_pk_add_u16 v1, v1, v3 clamp
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_uaddsat_v3i16:
diff --git a/llvm/test/CodeGen/AMDGPU/usubsat.ll b/llvm/test/CodeGen/AMDGPU/usubsat.ll
index 97bb4112ecdcd..549e39bd91739 100644
--- a/llvm/test/CodeGen/AMDGPU/usubsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/usubsat.ll
@@ -339,8 +339,8 @@ define <3 x i16> @v_usubsat_v3i16(<3 x i16> %lhs, <3 x i16> %rhs) {
 ; GFX9-LABEL: v_usubsat_v3i16:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_pk_sub_u16 v1, v1, v3 clamp
 ; GFX9-NEXT:    v_pk_sub_u16 v0, v0, v2 clamp
+; GFX9-NEXT:    v_pk_sub_u16 v1, v1, v3 clamp
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10PLUS-LABEL: v_usubsat_v3i16:

>From 7b79a7fa54fcbe053e1e8d11d38391e32772be6e Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 3 Jun 2026 10:59:15 +0800
Subject: [PATCH 2/7] using isNarrowingProfitable

---
 llvm/include/llvm/CodeGen/TargetLowering.h    |  7 -------
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 18 ++++++++++--------
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 12 ++++++++----
 llvm/lib/Target/AMDGPU/SIISelLowering.h       |  3 +--
 4 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index a57fd2ede44ea..82c47cce0f522 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -3527,13 +3527,6 @@ class LLVM_ABI TargetLoweringBase {
     return false;
   }
 
-  /// Return true if it is profitable to narrow a vector binop feeding an
-  /// extract_subvector into a binop of the extracted vector type.
-  virtual bool shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
-                                                unsigned Index) const {
-    return true;
-  }
-
   /// Return true if extraction of a scalar element from the given vector type
   /// at the given index is cheap. For example, if scalar operations occur on
   /// the same register file as vector operations, then an extract element may
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index c4c12fbf5dde6..904ae9eca08d6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27182,8 +27182,9 @@ static SDValue getSubVectorSrc(SDValue V, unsigned Index, EVT SubVT) {
   return SDValue();
 }
 
-static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
-                                              unsigned Index, const SDLoc &DL,
+static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
+                                              SDValue BinOp, unsigned Index,
+                                              const SDLoc &DL,
                                               SelectionDAG &DAG,
                                               bool LegalOperations) {
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -27192,7 +27193,7 @@ static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
     return SDValue();
 
   EVT VecVT = BinOp.getValueType();
-  if (!TLI.shouldNarrowExtractedVectorBinOp(VecVT, SubVT, Index))
+  if (!TLI.isNarrowingProfitable(N, VecVT, SubVT))
     return SDValue();
   SDValue Bop0 = BinOp.getOperand(0), Bop1 = BinOp.getOperand(1);
   if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType())
@@ -27217,13 +27218,14 @@ static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
 
 /// If we are extracting a subvector produced by a wide binary operator try
 /// to use a narrow binary operator and/or avoid concatenation and extraction.
-static SDValue narrowExtractedVectorBinOp(EVT VT, SDValue Src, unsigned Index,
-                                          const SDLoc &DL, SelectionDAG &DAG,
+static SDValue narrowExtractedVectorBinOp(SDNode *N, EVT VT, SDValue Src,
+                                          unsigned Index, const SDLoc &DL,
+                                          SelectionDAG &DAG,
                                           bool LegalOperations) {
   // TODO: Refactor with the caller (visitEXTRACT_SUBVECTOR), so we can share
   // some of these bailouts with other transforms.
 
-  if (SDValue V = narrowInsertExtractVectorBinOp(VT, Src, Index, DL, DAG,
+  if (SDValue V = narrowInsertExtractVectorBinOp(N, VT, Src, Index, DL, DAG,
                                                  LegalOperations))
     return V;
 
@@ -27689,8 +27691,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
           NVT, V, ExtIdx, DL, DAG, LegalOperations))
     return Shuffle;
 
-  if (SDValue NarrowBOp =
-          narrowExtractedVectorBinOp(NVT, V, ExtIdx, DL, DAG, LegalOperations))
+  if (SDValue NarrowBOp = narrowExtractedVectorBinOp(N, NVT, V, ExtIdx, DL, DAG,
+                                                     LegalOperations))
     return NarrowBOp;
 
   V = peekThroughBitcasts(V);
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index b735d00be58e7..1de00c71e74e1 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -2354,11 +2354,15 @@ bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
   return true;
 }
 
-bool SITargetLowering::shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
-                                                        unsigned Index) const {
-  unsigned ScalarBits = SubVT.getScalarSizeInBits();
+bool SITargetLowering::isNarrowingProfitable(SDNode *N, EVT SrcVT,
+                                             EVT DestVT) const {
+  if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR)
+    return AMDGPUTargetLowering::isNarrowingProfitable(N, SrcVT, DestVT);
+                                                
+  unsigned Index = N->getConstantOperandVal(1);
+  unsigned ScalarBits = DestVT.getScalarSizeInBits();
   unsigned OffsetBits = Index * ScalarBits;
-  unsigned SubvectorBits = SubVT.getSizeInBits();
+  unsigned SubvectorBits = DestVT.getSizeInBits();
 
   // If the extracted subvector starts on a dword boundary and has a dword
   // sized payload, keeping the original wide result is preferable because the
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 154faefb37ae1..eaac8072206b6 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -399,8 +399,7 @@ class SITargetLowering final : public AMDGPUTargetLowering {
 
   bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
                                         Type *Ty) const override;
-  bool shouldNarrowExtractedVectorBinOp(EVT SrcVT, EVT SubVT,
-                                        unsigned Index) const override;
+  bool isNarrowingProfitable(SDNode *N, EVT SrcVT, EVT DestVT) const override;
   bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                unsigned Index) const override;
   bool isExtractVecEltCheap(EVT VT, unsigned Index) const override;

>From 025abc5abafed7535aafe491bb71249cb00d93b9 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 3 Jun 2026 11:10:25 +0800
Subject: [PATCH 3/7] fix format

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

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 1de00c71e74e1..805ed69174cd9 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -2358,7 +2358,7 @@ bool SITargetLowering::isNarrowingProfitable(SDNode *N, EVT SrcVT,
                                              EVT DestVT) const {
   if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR)
     return AMDGPUTargetLowering::isNarrowingProfitable(N, SrcVT, DestVT);
-                                                
+
   unsigned Index = N->getConstantOperandVal(1);
   unsigned ScalarBits = DestVT.getScalarSizeInBits();
   unsigned OffsetBits = Index * ScalarBits;

>From fb51911755f79cf68f2c92885cde4ab3facfbec1 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 4 Jun 2026 14:59:11 +0800
Subject: [PATCH 4/7] blocking narrow if other non extract_subvector

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 25 ++---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     | 17 ----
 llvm/lib/Target/AMDGPU/SIISelLowering.h       |  2 +-
 .../extract-subvector-binop-wide-use.ll       | 29 ++++++
 llvm/test/CodeGen/X86/combine-fmul.ll         |  4 +-
 llvm/test/CodeGen/X86/fast-isel-store.ll      | 50 ++++------
 .../CodeGen/X86/machine-combiner-int-vec.ll   | 12 +--
 llvm/test/CodeGen/X86/vselect-minmax.ll       | 92 ++++++++++---------
 8 files changed, 119 insertions(+), 112 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 904ae9eca08d6..847a94ddc4236 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27182,9 +27182,8 @@ static SDValue getSubVectorSrc(SDValue V, unsigned Index, EVT SubVT) {
   return SDValue();
 }
 
-static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
-                                              SDValue BinOp, unsigned Index,
-                                              const SDLoc &DL,
+static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
+                                              unsigned Index, const SDLoc &DL,
                                               SelectionDAG &DAG,
                                               bool LegalOperations) {
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -27193,8 +27192,6 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
     return SDValue();
 
   EVT VecVT = BinOp.getValueType();
-  if (!TLI.isNarrowingProfitable(N, VecVT, SubVT))
-    return SDValue();
   SDValue Bop0 = BinOp.getOperand(0), Bop1 = BinOp.getOperand(1);
   if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType())
     return SDValue();
@@ -27210,6 +27207,13 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
   if (!Sub0 || !Sub1)
     return SDValue();
 
+  // Every user of the wide binop must be an EXTRACT_SUBVECTOR; otherwise the
+  // wide binop will still be needed and this transform would not eliminate it.
+  for (SDNode *User : BinOp->users()) {
+    if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR)
+      return SDValue();
+  }
+
   // We are inserting both operands of the wide binop only to extract back
   // to the narrow vector size. Eliminate all of the insert/extract:
   // ext (binop (ins ?, X, Index), (ins ?, Y, Index)), Index --> binop X, Y
@@ -27218,14 +27222,13 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
 
 /// If we are extracting a subvector produced by a wide binary operator try
 /// to use a narrow binary operator and/or avoid concatenation and extraction.
-static SDValue narrowExtractedVectorBinOp(SDNode *N, EVT VT, SDValue Src,
-                                          unsigned Index, const SDLoc &DL,
-                                          SelectionDAG &DAG,
+static SDValue narrowExtractedVectorBinOp(EVT VT, SDValue Src, unsigned Index,
+                                          const SDLoc &DL, SelectionDAG &DAG,
                                           bool LegalOperations) {
   // TODO: Refactor with the caller (visitEXTRACT_SUBVECTOR), so we can share
   // some of these bailouts with other transforms.
 
-  if (SDValue V = narrowInsertExtractVectorBinOp(N, VT, Src, Index, DL, DAG,
+  if (SDValue V = narrowInsertExtractVectorBinOp(VT, Src, Index, DL, DAG,
                                                  LegalOperations))
     return V;
 
@@ -27691,8 +27694,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
           NVT, V, ExtIdx, DL, DAG, LegalOperations))
     return Shuffle;
 
-  if (SDValue NarrowBOp = narrowExtractedVectorBinOp(N, NVT, V, ExtIdx, DL, DAG,
-                                                     LegalOperations))
+  if (SDValue NarrowBOp =
+          narrowExtractedVectorBinOp(NVT, V, ExtIdx, DL, DAG, LegalOperations))
     return NarrowBOp;
 
   V = peekThroughBitcasts(V);
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 805ed69174cd9..f49b1efb9808d 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -2354,23 +2354,6 @@ bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
   return true;
 }
 
-bool SITargetLowering::isNarrowingProfitable(SDNode *N, EVT SrcVT,
-                                             EVT DestVT) const {
-  if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR)
-    return AMDGPUTargetLowering::isNarrowingProfitable(N, SrcVT, DestVT);
-
-  unsigned Index = N->getConstantOperandVal(1);
-  unsigned ScalarBits = DestVT.getScalarSizeInBits();
-  unsigned OffsetBits = Index * ScalarBits;
-  unsigned SubvectorBits = DestVT.getSizeInBits();
-
-  // If the extracted subvector starts on a dword boundary and has a dword
-  // sized payload, keeping the original wide result is preferable because the
-  // subvector can be referenced directly through subregisters. Otherwise,
-  // narrowing may avoid element extraction or reconstruction.
-  return OffsetBits % 32 != 0 || SubvectorBits % 32 != 0;
-}
-
 bool SITargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                                unsigned Index) const {
   if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT))
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index eaac8072206b6..95ff5bba7cfff 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -399,7 +399,7 @@ class SITargetLowering final : public AMDGPUTargetLowering {
 
   bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
                                         Type *Ty) const override;
-  bool isNarrowingProfitable(SDNode *N, EVT SrcVT, EVT DestVT) const override;
+
   bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                unsigned Index) const override;
   bool isExtractVecEltCheap(EVT VT, unsigned Index) const override;
diff --git a/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
new file mode 100644
index 0000000000000..c4dcf7c4405b3
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
@@ -0,0 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1250 < %s | FileCheck --check-prefix=GFX1250 %s
+
+define <4 x i32> @insert_extract_and_inreg_v4i32(ptr addrspace(1) inreg %out_sub, <2 x i32> inreg %a, <2 x i32> inreg %b) {
+; GFX1250-LABEL: insert_extract_and_inreg_v4i32:
+; GFX1250:       ; %bb.0: ; %entry
+; GFX1250-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX1250-NEXT:    s_wait_kmcnt 0x0
+; GFX1250-NEXT:    s_and_b32 s2, s2, s16
+; GFX1250-NEXT:    s_and_b32 s3, s3, s17
+; GFX1250-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX1250-NEXT:    v_dual_mov_b32 v0, s2 :: v_dual_mov_b32 v1, s3
+; GFX1250-NEXT:    v_dual_mov_b32 v2, 0 :: v_dual_mov_b32 v3, s3
+; GFX1250-NEXT:    global_store_b64 v2, v[0:1], s[0:1]
+; GFX1250-NEXT:    s_wait_xcnt 0x0
+; GFX1250-NEXT:    v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, 0
+; GFX1250-NEXT:    v_mov_b32_e32 v2, s2
+; GFX1250-NEXT:    s_set_pc_i64 s[30:31]
+entry:
+  %v0 = call <4 x i32> @llvm.vector.insert.v4i32.v2i32(<4 x i32> zeroinitializer, <2 x i32> %a, i64 2)
+  %v1 = call <4 x i32> @llvm.vector.insert.v4i32.v2i32(<4 x i32> zeroinitializer, <2 x i32> %b, i64 2)
+  %r = and <4 x i32> %v0, %v1
+  %sub = call <2 x i32> @llvm.vector.extract.v2i32.v4i32(<4 x i32> %r, i64 2)
+  store <2 x i32> %sub, ptr addrspace(1) %out_sub, align 8
+  ret <4 x i32> %r
+}
+
+declare <4 x i32> @llvm.vector.insert.v4i32.v2i32(<4 x i32>, <2 x i32>, i64 immarg)
+declare <2 x i32> @llvm.vector.extract.v2i32.v4i32(<4 x i32>, i64 immarg)
diff --git a/llvm/test/CodeGen/X86/combine-fmul.ll b/llvm/test/CodeGen/X86/combine-fmul.ll
index c5966a81147e9..6f8a9b9350755 100644
--- a/llvm/test/CodeGen/X86/combine-fmul.ll
+++ b/llvm/test/CodeGen/X86/combine-fmul.ll
@@ -121,10 +121,10 @@ define <16 x float> @concat_fmul_self_v16f32_v4f32(<4 x float> %a0, <4 x float>
 define <8 x double> @concat_fmul_self_v8f64_v4f64(<4 x double> %a0, <4 x double> %a1) {
 ; SSE-LABEL: concat_fmul_self_v8f64_v4f64:
 ; SSE:       # %bb.0:
-; SSE-NEXT:    mulpd %xmm0, %xmm0
 ; SSE-NEXT:    mulpd %xmm1, %xmm1
 ; SSE-NEXT:    mulpd %xmm2, %xmm2
 ; SSE-NEXT:    mulpd %xmm3, %xmm3
+; SSE-NEXT:    mulpd %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX1OR2-LABEL: concat_fmul_self_v8f64_v4f64:
@@ -148,10 +148,10 @@ define <8 x double> @concat_fmul_self_v8f64_v4f64(<4 x double> %a0, <4 x double>
 define <16 x float> @concat_fmul_self_v16f32_v8f32(<8 x float> %a0, <8 x float> %a1) {
 ; SSE-LABEL: concat_fmul_self_v16f32_v8f32:
 ; SSE:       # %bb.0:
-; SSE-NEXT:    mulps %xmm0, %xmm0
 ; SSE-NEXT:    mulps %xmm1, %xmm1
 ; SSE-NEXT:    mulps %xmm2, %xmm2
 ; SSE-NEXT:    mulps %xmm3, %xmm3
+; SSE-NEXT:    mulps %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX1OR2-LABEL: concat_fmul_self_v16f32_v8f32:
diff --git a/llvm/test/CodeGen/X86/fast-isel-store.ll b/llvm/test/CodeGen/X86/fast-isel-store.ll
index eba538d213392..b804239b3f418 100644
--- a/llvm/test/CodeGen/X86/fast-isel-store.ll
+++ b/llvm/test/CodeGen/X86/fast-isel-store.ll
@@ -337,20 +337,19 @@ define <4 x double> @test_store_4xf64(ptr nocapture %addr, <4 x double> %value,
 ; X86-SSE-LABEL: test_store_4xf64:
 ; X86-SSE:       # %bb.0:
 ; X86-SSE-NEXT:    subl $12, %esp
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm3
 ; X86-SSE-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm1
 ; X86-SSE-NEXT:    addpd %xmm2, %xmm0
 ; X86-SSE-NEXT:    movupd %xmm0, (%eax)
-; X86-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X86-SSE-NEXT:    movupd %xmm1, 16(%eax)
 ; X86-SSE-NEXT:    addl $12, %esp
 ; X86-SSE-NEXT:    retl
 ;
 ; X64-SSE-LABEL: test_store_4xf64:
 ; X64-SSE:       # %bb.0:
+; X64-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X64-SSE-NEXT:    addpd %xmm2, %xmm0
 ; X64-SSE-NEXT:    movupd %xmm0, (%rdi)
-; X64-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X64-SSE-NEXT:    movupd %xmm1, 16(%rdi)
 ; X64-SSE-NEXT:    retq
 ;
@@ -375,20 +374,19 @@ define <4 x double> @test_store_4xf64_aligned(ptr nocapture %addr, <4 x double>
 ; X86-SSE-LABEL: test_store_4xf64_aligned:
 ; X86-SSE:       # %bb.0:
 ; X86-SSE-NEXT:    subl $12, %esp
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm3
 ; X86-SSE-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm1
 ; X86-SSE-NEXT:    addpd %xmm2, %xmm0
 ; X86-SSE-NEXT:    movapd %xmm0, (%eax)
-; X86-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X86-SSE-NEXT:    movapd %xmm1, 16(%eax)
 ; X86-SSE-NEXT:    addl $12, %esp
 ; X86-SSE-NEXT:    retl
 ;
 ; X64-SSE-LABEL: test_store_4xf64_aligned:
 ; X64-SSE:       # %bb.0:
+; X64-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X64-SSE-NEXT:    addpd %xmm2, %xmm0
 ; X64-SSE-NEXT:    movapd %xmm0, (%rdi)
-; X64-SSE-NEXT:    addpd %xmm3, %xmm1
 ; X64-SSE-NEXT:    movapd %xmm1, 16(%rdi)
 ; X64-SSE-NEXT:    retq
 ;
@@ -605,17 +603,14 @@ define <8 x double> @test_store_8xf64(ptr nocapture %addr, <8 x double> %value,
 ; X86-SSE-LABEL: test_store_8xf64:
 ; X86-SSE:       # %bb.0:
 ; X86-SSE-NEXT:    subl $12, %esp
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm4
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm5
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm6
 ; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm3
-; X86-SSE-NEXT:    addpd %xmm4, %xmm3
 ; X86-SSE-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm3
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm2
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm1
 ; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm0
 ; X86-SSE-NEXT:    movupd %xmm0, (%eax)
-; X86-SSE-NEXT:    addpd %xmm6, %xmm1
 ; X86-SSE-NEXT:    movupd %xmm1, 16(%eax)
-; X86-SSE-NEXT:    addpd %xmm5, %xmm2
 ; X86-SSE-NEXT:    movupd %xmm2, 32(%eax)
 ; X86-SSE-NEXT:    movupd %xmm3, 48(%eax)
 ; X86-SSE-NEXT:    addl $12, %esp
@@ -623,13 +618,13 @@ define <8 x double> @test_store_8xf64(ptr nocapture %addr, <8 x double> %value,
 ;
 ; X64-SSE-LABEL: test_store_8xf64:
 ; X64-SSE:       # %bb.0:
+; X64-SSE-NEXT:    addpd %xmm7, %xmm3
+; X64-SSE-NEXT:    addpd %xmm6, %xmm2
+; X64-SSE-NEXT:    addpd %xmm5, %xmm1
 ; X64-SSE-NEXT:    addpd %xmm4, %xmm0
 ; X64-SSE-NEXT:    movupd %xmm0, (%rdi)
-; X64-SSE-NEXT:    addpd %xmm5, %xmm1
 ; X64-SSE-NEXT:    movupd %xmm1, 16(%rdi)
-; X64-SSE-NEXT:    addpd %xmm6, %xmm2
 ; X64-SSE-NEXT:    movupd %xmm2, 32(%rdi)
-; X64-SSE-NEXT:    addpd %xmm7, %xmm3
 ; X64-SSE-NEXT:    movupd %xmm3, 48(%rdi)
 ; X64-SSE-NEXT:    retq
 ;
@@ -639,11 +634,10 @@ define <8 x double> @test_store_8xf64(ptr nocapture %addr, <8 x double> %value,
 ; X86-AVX1-NEXT:    movl %esp, %ebp
 ; X86-AVX1-NEXT:    andl $-32, %esp
 ; X86-AVX1-NEXT:    subl $32, %esp
-; X86-AVX1-NEXT:    vmovapd 40(%ebp), %ymm3
 ; X86-AVX1-NEXT:    movl 8(%ebp), %eax
+; X86-AVX1-NEXT:    vaddpd 40(%ebp), %ymm1, %ymm1
 ; X86-AVX1-NEXT:    vaddpd %ymm2, %ymm0, %ymm0
 ; X86-AVX1-NEXT:    vmovupd %ymm0, (%eax)
-; X86-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X86-AVX1-NEXT:    vmovupd %ymm1, 32(%eax)
 ; X86-AVX1-NEXT:    movl %ebp, %esp
 ; X86-AVX1-NEXT:    popl %ebp
@@ -651,9 +645,9 @@ define <8 x double> @test_store_8xf64(ptr nocapture %addr, <8 x double> %value,
 ;
 ; X64-AVX1-LABEL: test_store_8xf64:
 ; X64-AVX1:       # %bb.0:
+; X64-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X64-AVX1-NEXT:    vaddpd %ymm2, %ymm0, %ymm0
 ; X64-AVX1-NEXT:    vmovupd %ymm0, (%rdi)
-; X64-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X64-AVX1-NEXT:    vmovupd %ymm1, 32(%rdi)
 ; X64-AVX1-NEXT:    retq
 ;
@@ -678,17 +672,14 @@ define <8 x double> @test_store_8xf64_aligned(ptr nocapture %addr, <8 x double>
 ; X86-SSE-LABEL: test_store_8xf64_aligned:
 ; X86-SSE:       # %bb.0:
 ; X86-SSE-NEXT:    subl $12, %esp
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm4
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm5
-; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm6
 ; X86-SSE-NEXT:    movapd {{[0-9]+}}(%esp), %xmm3
-; X86-SSE-NEXT:    addpd %xmm4, %xmm3
 ; X86-SSE-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm3
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm2
+; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm1
 ; X86-SSE-NEXT:    addpd {{[0-9]+}}(%esp), %xmm0
 ; X86-SSE-NEXT:    movapd %xmm0, (%eax)
-; X86-SSE-NEXT:    addpd %xmm6, %xmm1
 ; X86-SSE-NEXT:    movapd %xmm1, 16(%eax)
-; X86-SSE-NEXT:    addpd %xmm5, %xmm2
 ; X86-SSE-NEXT:    movapd %xmm2, 32(%eax)
 ; X86-SSE-NEXT:    movapd %xmm3, 48(%eax)
 ; X86-SSE-NEXT:    addl $12, %esp
@@ -696,13 +687,13 @@ define <8 x double> @test_store_8xf64_aligned(ptr nocapture %addr, <8 x double>
 ;
 ; X64-SSE-LABEL: test_store_8xf64_aligned:
 ; X64-SSE:       # %bb.0:
+; X64-SSE-NEXT:    addpd %xmm7, %xmm3
+; X64-SSE-NEXT:    addpd %xmm6, %xmm2
+; X64-SSE-NEXT:    addpd %xmm5, %xmm1
 ; X64-SSE-NEXT:    addpd %xmm4, %xmm0
 ; X64-SSE-NEXT:    movapd %xmm0, (%rdi)
-; X64-SSE-NEXT:    addpd %xmm5, %xmm1
 ; X64-SSE-NEXT:    movapd %xmm1, 16(%rdi)
-; X64-SSE-NEXT:    addpd %xmm6, %xmm2
 ; X64-SSE-NEXT:    movapd %xmm2, 32(%rdi)
-; X64-SSE-NEXT:    addpd %xmm7, %xmm3
 ; X64-SSE-NEXT:    movapd %xmm3, 48(%rdi)
 ; X64-SSE-NEXT:    retq
 ;
@@ -712,11 +703,10 @@ define <8 x double> @test_store_8xf64_aligned(ptr nocapture %addr, <8 x double>
 ; X86-AVX1-NEXT:    movl %esp, %ebp
 ; X86-AVX1-NEXT:    andl $-32, %esp
 ; X86-AVX1-NEXT:    subl $32, %esp
-; X86-AVX1-NEXT:    vmovapd 40(%ebp), %ymm3
 ; X86-AVX1-NEXT:    movl 8(%ebp), %eax
+; X86-AVX1-NEXT:    vaddpd 40(%ebp), %ymm1, %ymm1
 ; X86-AVX1-NEXT:    vaddpd %ymm2, %ymm0, %ymm0
 ; X86-AVX1-NEXT:    vmovapd %ymm0, (%eax)
-; X86-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X86-AVX1-NEXT:    vmovapd %ymm1, 32(%eax)
 ; X86-AVX1-NEXT:    movl %ebp, %esp
 ; X86-AVX1-NEXT:    popl %ebp
@@ -724,9 +714,9 @@ define <8 x double> @test_store_8xf64_aligned(ptr nocapture %addr, <8 x double>
 ;
 ; X64-AVX1-LABEL: test_store_8xf64_aligned:
 ; X64-AVX1:       # %bb.0:
+; X64-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X64-AVX1-NEXT:    vaddpd %ymm2, %ymm0, %ymm0
 ; X64-AVX1-NEXT:    vmovapd %ymm0, (%rdi)
-; X64-AVX1-NEXT:    vaddpd %ymm3, %ymm1, %ymm1
 ; X64-AVX1-NEXT:    vmovapd %ymm1, 32(%rdi)
 ; X64-AVX1-NEXT:    retq
 ;
diff --git a/llvm/test/CodeGen/X86/machine-combiner-int-vec.ll b/llvm/test/CodeGen/X86/machine-combiner-int-vec.ll
index ee42cb8126f74..9cb026ff009c7 100644
--- a/llvm/test/CodeGen/X86/machine-combiner-int-vec.ll
+++ b/llvm/test/CodeGen/X86/machine-combiner-int-vec.ll
@@ -91,10 +91,10 @@ define <4 x i32> @reassociate_xor_v4i32(<4 x i32> %x0, <4 x i32> %x1, <4 x i32>
 define <8 x i32> @reassociate_and_v8i32(<8 x i32> %x0, <8 x i32> %x1, <8 x i32> %x2, <8 x i32> %x3) {
 ; SSE-LABEL: reassociate_and_v8i32:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    paddd %xmm2, %xmm0
 ; SSE-NEXT:    pand %xmm6, %xmm4
 ; SSE-NEXT:    pand %xmm4, %xmm0
-; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    pand %xmm7, %xmm5
 ; SSE-NEXT:    pand %xmm5, %xmm1
 ; SSE-NEXT:    retq
@@ -121,10 +121,10 @@ define <8 x i32> @reassociate_and_v8i32(<8 x i32> %x0, <8 x i32> %x1, <8 x i32>
 define <8 x i32> @reassociate_or_v8i32(<8 x i32> %x0, <8 x i32> %x1, <8 x i32> %x2, <8 x i32> %x3) {
 ; SSE-LABEL: reassociate_or_v8i32:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    paddd %xmm2, %xmm0
 ; SSE-NEXT:    por %xmm6, %xmm4
 ; SSE-NEXT:    por %xmm4, %xmm0
-; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    por %xmm7, %xmm5
 ; SSE-NEXT:    por %xmm5, %xmm1
 ; SSE-NEXT:    retq
@@ -151,10 +151,10 @@ define <8 x i32> @reassociate_or_v8i32(<8 x i32> %x0, <8 x i32> %x1, <8 x i32> %
 define <8 x i32> @reassociate_xor_v8i32(<8 x i32> %x0, <8 x i32> %x1, <8 x i32> %x2, <8 x i32> %x3) {
 ; SSE-LABEL: reassociate_xor_v8i32:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    paddd %xmm2, %xmm0
 ; SSE-NEXT:    pxor %xmm6, %xmm4
 ; SSE-NEXT:    pxor %xmm4, %xmm0
-; SSE-NEXT:    paddd %xmm3, %xmm1
 ; SSE-NEXT:    pxor %xmm7, %xmm5
 ; SSE-NEXT:    pxor %xmm5, %xmm1
 ; SSE-NEXT:    retq
@@ -200,10 +200,10 @@ define <16 x i32> @reassociate_and_v16i32(<16 x i32> %x0, <16 x i32> %x1, <16 x
 ;
 ; AVX2-LABEL: reassociate_and_v16i32:
 ; AVX2:       # %bb.0:
+; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpaddd %ymm2, %ymm0, %ymm0
 ; AVX2-NEXT:    vpand %ymm4, %ymm6, %ymm2
 ; AVX2-NEXT:    vpand %ymm0, %ymm2, %ymm0
-; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpand %ymm5, %ymm7, %ymm2
 ; AVX2-NEXT:    vpand %ymm1, %ymm2, %ymm1
 ; AVX2-NEXT:    retq
@@ -239,10 +239,10 @@ define <16 x i32> @reassociate_or_v16i32(<16 x i32> %x0, <16 x i32> %x1, <16 x i
 ;
 ; AVX2-LABEL: reassociate_or_v16i32:
 ; AVX2:       # %bb.0:
+; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpaddd %ymm2, %ymm0, %ymm0
 ; AVX2-NEXT:    vpor %ymm4, %ymm6, %ymm2
 ; AVX2-NEXT:    vpor %ymm0, %ymm2, %ymm0
-; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpor %ymm5, %ymm7, %ymm2
 ; AVX2-NEXT:    vpor %ymm1, %ymm2, %ymm1
 ; AVX2-NEXT:    retq
@@ -278,10 +278,10 @@ define <16 x i32> @reassociate_xor_v16i32(<16 x i32> %x0, <16 x i32> %x1, <16 x
 ;
 ; AVX2-LABEL: reassociate_xor_v16i32:
 ; AVX2:       # %bb.0:
+; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpaddd %ymm2, %ymm0, %ymm0
 ; AVX2-NEXT:    vpxor %ymm4, %ymm6, %ymm2
 ; AVX2-NEXT:    vpxor %ymm0, %ymm2, %ymm0
-; AVX2-NEXT:    vpaddd %ymm3, %ymm1, %ymm1
 ; AVX2-NEXT:    vpxor %ymm5, %ymm7, %ymm2
 ; AVX2-NEXT:    vpxor %ymm1, %ymm2, %ymm1
 ; AVX2-NEXT:    retq
diff --git a/llvm/test/CodeGen/X86/vselect-minmax.ll b/llvm/test/CodeGen/X86/vselect-minmax.ll
index cb0542ca7cea8..2352b6d6c0b8f 100644
--- a/llvm/test/CodeGen/X86/vselect-minmax.ll
+++ b/llvm/test/CodeGen/X86/vselect-minmax.ll
@@ -10284,69 +10284,71 @@ define <8 x i64> @concat_smin_smax(<4 x i64> %a0, <4 x i64> %a1) {
 ; SSE2-LABEL: concat_smin_smax:
 ; SSE2:       # %bb.0:
 ; SSE2-NEXT:    movdqa {{.*#+}} xmm6 = [2147483648,2147483648]
-; SSE2-NEXT:    movdqa %xmm0, %xmm4
+; SSE2-NEXT:    movdqa %xmm3, %xmm4
 ; SSE2-NEXT:    pxor %xmm6, %xmm4
-; SSE2-NEXT:    movdqa %xmm2, %xmm5
+; SSE2-NEXT:    movdqa %xmm1, %xmm5
 ; SSE2-NEXT:    pxor %xmm6, %xmm5
 ; SSE2-NEXT:    movdqa %xmm5, %xmm7
 ; SSE2-NEXT:    pcmpgtd %xmm4, %xmm7
 ; SSE2-NEXT:    pshufd {{.*#+}} xmm8 = xmm7[0,0,2,2]
 ; SSE2-NEXT:    pcmpeqd %xmm4, %xmm5
-; SSE2-NEXT:    pshufd {{.*#+}} xmm4 = xmm5[1,1,3,3]
-; SSE2-NEXT:    pand %xmm8, %xmm4
-; SSE2-NEXT:    pshufd {{.*#+}} xmm5 = xmm7[1,1,3,3]
-; SSE2-NEXT:    por %xmm4, %xmm5
-; SSE2-NEXT:    movdqa %xmm5, %xmm7
-; SSE2-NEXT:    pandn %xmm2, %xmm7
-; SSE2-NEXT:    movdqa %xmm0, %xmm4
-; SSE2-NEXT:    pand %xmm5, %xmm4
-; SSE2-NEXT:    por %xmm7, %xmm4
-; SSE2-NEXT:    movdqa %xmm1, %xmm7
+; SSE2-NEXT:    pshufd {{.*#+}} xmm5 = xmm5[1,1,3,3]
+; SSE2-NEXT:    pand %xmm8, %xmm5
+; SSE2-NEXT:    pshufd {{.*#+}} xmm4 = xmm7[1,1,3,3]
+; SSE2-NEXT:    por %xmm5, %xmm4
+; SSE2-NEXT:    movdqa %xmm4, %xmm7
+; SSE2-NEXT:    pandn %xmm1, %xmm7
+; SSE2-NEXT:    movdqa %xmm3, %xmm5
+; SSE2-NEXT:    pand %xmm4, %xmm5
+; SSE2-NEXT:    por %xmm7, %xmm5
+; SSE2-NEXT:    movdqa %xmm2, %xmm7
 ; SSE2-NEXT:    pxor %xmm6, %xmm7
-; SSE2-NEXT:    pxor %xmm3, %xmm6
+; SSE2-NEXT:    pxor %xmm0, %xmm6
 ; SSE2-NEXT:    movdqa %xmm6, %xmm8
 ; SSE2-NEXT:    pcmpgtd %xmm7, %xmm8
 ; SSE2-NEXT:    pshufd {{.*#+}} xmm9 = xmm8[0,0,2,2]
 ; SSE2-NEXT:    pcmpeqd %xmm7, %xmm6
-; SSE2-NEXT:    pshufd {{.*#+}} xmm6 = xmm6[1,1,3,3]
-; SSE2-NEXT:    pand %xmm9, %xmm6
-; SSE2-NEXT:    pshufd {{.*#+}} xmm7 = xmm8[1,1,3,3]
-; SSE2-NEXT:    por %xmm6, %xmm7
-; SSE2-NEXT:    movdqa %xmm7, %xmm6
-; SSE2-NEXT:    pandn %xmm3, %xmm6
-; SSE2-NEXT:    movdqa %xmm7, %xmm8
-; SSE2-NEXT:    pandn %xmm1, %xmm8
-; SSE2-NEXT:    pand %xmm7, %xmm1
-; SSE2-NEXT:    por %xmm6, %xmm1
-; SSE2-NEXT:    pand %xmm5, %xmm2
-; SSE2-NEXT:    pandn %xmm0, %xmm5
-; SSE2-NEXT:    por %xmm5, %xmm2
-; SSE2-NEXT:    pand %xmm7, %xmm3
-; SSE2-NEXT:    por %xmm8, %xmm3
-; SSE2-NEXT:    movdqa %xmm4, %xmm0
+; SSE2-NEXT:    pshufd {{.*#+}} xmm7 = xmm6[1,1,3,3]
+; SSE2-NEXT:    pand %xmm9, %xmm7
+; SSE2-NEXT:    pshufd {{.*#+}} xmm6 = xmm8[1,1,3,3]
+; SSE2-NEXT:    por %xmm7, %xmm6
+; SSE2-NEXT:    movdqa %xmm6, %xmm7
+; SSE2-NEXT:    pandn %xmm2, %xmm7
+; SSE2-NEXT:    movdqa %xmm6, %xmm8
+; SSE2-NEXT:    pandn %xmm0, %xmm8
+; SSE2-NEXT:    pand %xmm6, %xmm0
+; SSE2-NEXT:    por %xmm0, %xmm7
+; SSE2-NEXT:    pand %xmm4, %xmm1
+; SSE2-NEXT:    pandn %xmm3, %xmm4
+; SSE2-NEXT:    por %xmm1, %xmm4
+; SSE2-NEXT:    pand %xmm2, %xmm6
+; SSE2-NEXT:    por %xmm8, %xmm6
+; SSE2-NEXT:    movdqa %xmm6, %xmm0
+; SSE2-NEXT:    movdqa %xmm5, %xmm1
+; SSE2-NEXT:    movdqa %xmm7, %xmm2
+; SSE2-NEXT:    movdqa %xmm4, %xmm3
 ; SSE2-NEXT:    retq
 ;
 ; SSE4-LABEL: concat_smin_smax:
 ; SSE4:       # %bb.0:
-; SSE4-NEXT:    movdqa %xmm1, %xmm4
-; SSE4-NEXT:    movdqa %xmm0, %xmm5
+; SSE4-NEXT:    movdqa %xmm0, %xmm4
+; SSE4-NEXT:    movdqa %xmm1, %xmm5
+; SSE4-NEXT:    pcmpgtq %xmm3, %xmm5
+; SSE4-NEXT:    movdqa %xmm1, %xmm6
+; SSE4-NEXT:    movdqa %xmm5, %xmm0
+; SSE4-NEXT:    blendvpd %xmm0, %xmm3, %xmm6
+; SSE4-NEXT:    movdqa %xmm4, %xmm7
+; SSE4-NEXT:    pcmpgtq %xmm2, %xmm7
 ; SSE4-NEXT:    movdqa %xmm2, %xmm8
-; SSE4-NEXT:    pcmpgtq %xmm0, %xmm8
-; SSE4-NEXT:    movdqa %xmm2, %xmm6
-; SSE4-NEXT:    movdqa %xmm8, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm5, %xmm6
-; SSE4-NEXT:    movdqa %xmm3, %xmm7
-; SSE4-NEXT:    pcmpgtq %xmm1, %xmm7
-; SSE4-NEXT:    movdqa %xmm3, %xmm1
 ; SSE4-NEXT:    movdqa %xmm7, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm4, %xmm1
-; SSE4-NEXT:    movdqa %xmm8, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm2, %xmm5
+; SSE4-NEXT:    blendvpd %xmm0, %xmm4, %xmm8
+; SSE4-NEXT:    movdqa %xmm5, %xmm0
+; SSE4-NEXT:    blendvpd %xmm0, %xmm1, %xmm3
 ; SSE4-NEXT:    movdqa %xmm7, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm3, %xmm4
-; SSE4-NEXT:    movapd %xmm6, %xmm0
-; SSE4-NEXT:    movapd %xmm5, %xmm2
-; SSE4-NEXT:    movapd %xmm4, %xmm3
+; SSE4-NEXT:    blendvpd %xmm0, %xmm2, %xmm4
+; SSE4-NEXT:    movapd %xmm4, %xmm0
+; SSE4-NEXT:    movapd %xmm6, %xmm1
+; SSE4-NEXT:    movapd %xmm8, %xmm2
 ; SSE4-NEXT:    retq
 ;
 ; AVX1-LABEL: concat_smin_smax:

>From 587967a547aba64ebf5b67af50eb1910e4f719b2 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 4 Jun 2026 17:30:02 +0800
Subject: [PATCH 5/7] fix bug

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 25 +++++---
 llvm/test/CodeGen/X86/combine-fmul.ll         |  4 +-
 llvm/test/CodeGen/X86/nontemporal-2.ll        |  2 +-
 llvm/test/CodeGen/X86/vselect-minmax.ll       | 61 +++++++++----------
 4 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 847a94ddc4236..b66933120ecc3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27182,8 +27182,9 @@ static SDValue getSubVectorSrc(SDValue V, unsigned Index, EVT SubVT) {
   return SDValue();
 }
 
-static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
-                                              unsigned Index, const SDLoc &DL,
+static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
+                                              SDValue BinOp, unsigned Index,
+                                              const SDLoc &DL,
                                               SelectionDAG &DAG,
                                               bool LegalOperations) {
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -27207,10 +27208,13 @@ static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
   if (!Sub0 || !Sub1)
     return SDValue();
 
-  // Every user of the wide binop must be an EXTRACT_SUBVECTOR; otherwise the
-  // wide binop will still be needed and this transform would not eliminate it.
+  // Every other user of the wide binop must be an EXTRACT_SUBVECTOR that is
+  // still on the combiner worklist; otherwise the wide binop may remain needed.
   for (SDNode *User : BinOp->users()) {
-    if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR)
+    if (User == N)
+      continue;
+    if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
+        User->getCombinerWorklistIndex() < 0)
       return SDValue();
   }
 
@@ -27222,13 +27226,14 @@ static SDValue narrowInsertExtractVectorBinOp(EVT SubVT, SDValue BinOp,
 
 /// If we are extracting a subvector produced by a wide binary operator try
 /// to use a narrow binary operator and/or avoid concatenation and extraction.
-static SDValue narrowExtractedVectorBinOp(EVT VT, SDValue Src, unsigned Index,
-                                          const SDLoc &DL, SelectionDAG &DAG,
+static SDValue narrowExtractedVectorBinOp(SDNode *N, EVT VT, SDValue Src,
+                                          unsigned Index, const SDLoc &DL,
+                                          SelectionDAG &DAG,
                                           bool LegalOperations) {
   // TODO: Refactor with the caller (visitEXTRACT_SUBVECTOR), so we can share
   // some of these bailouts with other transforms.
 
-  if (SDValue V = narrowInsertExtractVectorBinOp(VT, Src, Index, DL, DAG,
+  if (SDValue V = narrowInsertExtractVectorBinOp(N, VT, Src, Index, DL, DAG,
                                                  LegalOperations))
     return V;
 
@@ -27694,8 +27699,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
           NVT, V, ExtIdx, DL, DAG, LegalOperations))
     return Shuffle;
 
-  if (SDValue NarrowBOp =
-          narrowExtractedVectorBinOp(NVT, V, ExtIdx, DL, DAG, LegalOperations))
+  if (SDValue NarrowBOp = narrowExtractedVectorBinOp(N, NVT, V, ExtIdx, DL, DAG,
+                                                     LegalOperations))
     return NarrowBOp;
 
   V = peekThroughBitcasts(V);
diff --git a/llvm/test/CodeGen/X86/combine-fmul.ll b/llvm/test/CodeGen/X86/combine-fmul.ll
index 6f8a9b9350755..c5966a81147e9 100644
--- a/llvm/test/CodeGen/X86/combine-fmul.ll
+++ b/llvm/test/CodeGen/X86/combine-fmul.ll
@@ -121,10 +121,10 @@ define <16 x float> @concat_fmul_self_v16f32_v4f32(<4 x float> %a0, <4 x float>
 define <8 x double> @concat_fmul_self_v8f64_v4f64(<4 x double> %a0, <4 x double> %a1) {
 ; SSE-LABEL: concat_fmul_self_v8f64_v4f64:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    mulpd %xmm0, %xmm0
 ; SSE-NEXT:    mulpd %xmm1, %xmm1
 ; SSE-NEXT:    mulpd %xmm2, %xmm2
 ; SSE-NEXT:    mulpd %xmm3, %xmm3
-; SSE-NEXT:    mulpd %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX1OR2-LABEL: concat_fmul_self_v8f64_v4f64:
@@ -148,10 +148,10 @@ define <8 x double> @concat_fmul_self_v8f64_v4f64(<4 x double> %a0, <4 x double>
 define <16 x float> @concat_fmul_self_v16f32_v8f32(<8 x float> %a0, <8 x float> %a1) {
 ; SSE-LABEL: concat_fmul_self_v16f32_v8f32:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    mulps %xmm0, %xmm0
 ; SSE-NEXT:    mulps %xmm1, %xmm1
 ; SSE-NEXT:    mulps %xmm2, %xmm2
 ; SSE-NEXT:    mulps %xmm3, %xmm3
-; SSE-NEXT:    mulps %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX1OR2-LABEL: concat_fmul_self_v16f32_v8f32:
diff --git a/llvm/test/CodeGen/X86/nontemporal-2.ll b/llvm/test/CodeGen/X86/nontemporal-2.ll
index e5f217301956a..f9795d869b3e7 100644
--- a/llvm/test/CodeGen/X86/nontemporal-2.ll
+++ b/llvm/test/CodeGen/X86/nontemporal-2.ll
@@ -1234,9 +1234,9 @@ define void @test_op_v32i8(<32 x i8> %a, <32 x i8> %b, ptr %dst) {
 define void @test_unaligned_v8f32(<8 x float> %a, <8 x float> %b, ptr %dst) {
 ; SSE-LABEL: test_unaligned_v8f32:
 ; SSE:       # %bb.0:
+; SSE-NEXT:    addps %xmm2, %xmm0
 ; SSE-NEXT:    addps %xmm3, %xmm1
 ; SSE-NEXT:    movntps %xmm1, 16(%rdi)
-; SSE-NEXT:    addps %xmm2, %xmm0
 ; SSE-NEXT:    movntps %xmm0, (%rdi)
 ; SSE-NEXT:    retq
 ;
diff --git a/llvm/test/CodeGen/X86/vselect-minmax.ll b/llvm/test/CodeGen/X86/vselect-minmax.ll
index 2352b6d6c0b8f..57f18714c11d0 100644
--- a/llvm/test/CodeGen/X86/vselect-minmax.ll
+++ b/llvm/test/CodeGen/X86/vselect-minmax.ll
@@ -10284,9 +10284,9 @@ define <8 x i64> @concat_smin_smax(<4 x i64> %a0, <4 x i64> %a1) {
 ; SSE2-LABEL: concat_smin_smax:
 ; SSE2:       # %bb.0:
 ; SSE2-NEXT:    movdqa {{.*#+}} xmm6 = [2147483648,2147483648]
-; SSE2-NEXT:    movdqa %xmm3, %xmm4
+; SSE2-NEXT:    movdqa %xmm2, %xmm4
 ; SSE2-NEXT:    pxor %xmm6, %xmm4
-; SSE2-NEXT:    movdqa %xmm1, %xmm5
+; SSE2-NEXT:    movdqa %xmm0, %xmm5
 ; SSE2-NEXT:    pxor %xmm6, %xmm5
 ; SSE2-NEXT:    movdqa %xmm5, %xmm7
 ; SSE2-NEXT:    pcmpgtd %xmm4, %xmm7
@@ -10297,13 +10297,13 @@ define <8 x i64> @concat_smin_smax(<4 x i64> %a0, <4 x i64> %a1) {
 ; SSE2-NEXT:    pshufd {{.*#+}} xmm4 = xmm7[1,1,3,3]
 ; SSE2-NEXT:    por %xmm5, %xmm4
 ; SSE2-NEXT:    movdqa %xmm4, %xmm7
-; SSE2-NEXT:    pandn %xmm1, %xmm7
-; SSE2-NEXT:    movdqa %xmm3, %xmm5
+; SSE2-NEXT:    pandn %xmm0, %xmm7
+; SSE2-NEXT:    movdqa %xmm2, %xmm5
 ; SSE2-NEXT:    pand %xmm4, %xmm5
 ; SSE2-NEXT:    por %xmm7, %xmm5
-; SSE2-NEXT:    movdqa %xmm2, %xmm7
+; SSE2-NEXT:    movdqa %xmm3, %xmm7
 ; SSE2-NEXT:    pxor %xmm6, %xmm7
-; SSE2-NEXT:    pxor %xmm0, %xmm6
+; SSE2-NEXT:    pxor %xmm1, %xmm6
 ; SSE2-NEXT:    movdqa %xmm6, %xmm8
 ; SSE2-NEXT:    pcmpgtd %xmm7, %xmm8
 ; SSE2-NEXT:    pshufd {{.*#+}} xmm9 = xmm8[0,0,2,2]
@@ -10313,42 +10313,41 @@ define <8 x i64> @concat_smin_smax(<4 x i64> %a0, <4 x i64> %a1) {
 ; SSE2-NEXT:    pshufd {{.*#+}} xmm6 = xmm8[1,1,3,3]
 ; SSE2-NEXT:    por %xmm7, %xmm6
 ; SSE2-NEXT:    movdqa %xmm6, %xmm7
-; SSE2-NEXT:    pandn %xmm2, %xmm7
+; SSE2-NEXT:    pandn %xmm1, %xmm7
 ; SSE2-NEXT:    movdqa %xmm6, %xmm8
-; SSE2-NEXT:    pandn %xmm0, %xmm8
-; SSE2-NEXT:    pand %xmm6, %xmm0
-; SSE2-NEXT:    por %xmm0, %xmm7
-; SSE2-NEXT:    pand %xmm4, %xmm1
-; SSE2-NEXT:    pandn %xmm3, %xmm4
-; SSE2-NEXT:    por %xmm1, %xmm4
-; SSE2-NEXT:    pand %xmm2, %xmm6
+; SSE2-NEXT:    pandn %xmm3, %xmm8
+; SSE2-NEXT:    pand %xmm6, %xmm3
+; SSE2-NEXT:    por %xmm3, %xmm7
+; SSE2-NEXT:    pand %xmm4, %xmm0
+; SSE2-NEXT:    pandn %xmm2, %xmm4
+; SSE2-NEXT:    por %xmm0, %xmm4
+; SSE2-NEXT:    pand %xmm1, %xmm6
 ; SSE2-NEXT:    por %xmm8, %xmm6
-; SSE2-NEXT:    movdqa %xmm6, %xmm0
-; SSE2-NEXT:    movdqa %xmm5, %xmm1
-; SSE2-NEXT:    movdqa %xmm7, %xmm2
-; SSE2-NEXT:    movdqa %xmm4, %xmm3
+; SSE2-NEXT:    movdqa %xmm5, %xmm0
+; SSE2-NEXT:    movdqa %xmm7, %xmm1
+; SSE2-NEXT:    movdqa %xmm4, %xmm2
+; SSE2-NEXT:    movdqa %xmm6, %xmm3
 ; SSE2-NEXT:    retq
 ;
 ; SSE4-LABEL: concat_smin_smax:
 ; SSE4:       # %bb.0:
 ; SSE4-NEXT:    movdqa %xmm0, %xmm4
-; SSE4-NEXT:    movdqa %xmm1, %xmm5
-; SSE4-NEXT:    pcmpgtq %xmm3, %xmm5
-; SSE4-NEXT:    movdqa %xmm1, %xmm6
+; SSE4-NEXT:    movdqa %xmm0, %xmm5
+; SSE4-NEXT:    pcmpgtq %xmm2, %xmm5
+; SSE4-NEXT:    movdqa %xmm0, %xmm6
 ; SSE4-NEXT:    movdqa %xmm5, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm3, %xmm6
-; SSE4-NEXT:    movdqa %xmm4, %xmm7
-; SSE4-NEXT:    pcmpgtq %xmm2, %xmm7
-; SSE4-NEXT:    movdqa %xmm2, %xmm8
+; SSE4-NEXT:    blendvpd %xmm0, %xmm2, %xmm6
+; SSE4-NEXT:    movdqa %xmm1, %xmm7
+; SSE4-NEXT:    pcmpgtq %xmm3, %xmm7
+; SSE4-NEXT:    movdqa %xmm1, %xmm8
 ; SSE4-NEXT:    movdqa %xmm7, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm4, %xmm8
+; SSE4-NEXT:    blendvpd %xmm0, %xmm3, %xmm8
 ; SSE4-NEXT:    movdqa %xmm5, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm1, %xmm3
+; SSE4-NEXT:    blendvpd %xmm0, %xmm4, %xmm2
 ; SSE4-NEXT:    movdqa %xmm7, %xmm0
-; SSE4-NEXT:    blendvpd %xmm0, %xmm2, %xmm4
-; SSE4-NEXT:    movapd %xmm4, %xmm0
-; SSE4-NEXT:    movapd %xmm6, %xmm1
-; SSE4-NEXT:    movapd %xmm8, %xmm2
+; SSE4-NEXT:    blendvpd %xmm0, %xmm1, %xmm3
+; SSE4-NEXT:    movapd %xmm6, %xmm0
+; SSE4-NEXT:    movapd %xmm8, %xmm1
 ; SSE4-NEXT:    retq
 ;
 ; AVX1-LABEL: concat_smin_smax:

>From 2c8588400a33f9eac1a2960e94f07748c596be6c Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 8 Jun 2026 13:36:07 +0800
Subject: [PATCH 6/7] convert all extract when first meet

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 125 ++++++++++++------
 llvm/test/CodeGen/X86/vector-narrow-binop.ll  |   4 +-
 2 files changed, 87 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 2d60b15bf2fdb..b2ddeb5a8f5e7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallBitVector.h"
@@ -27170,26 +27171,55 @@ SDValue DAGCombiner::visitVECTOR_INTERLEAVE(SDNode *N) {
   return CombineTo(N, &Ops);
 }
 
-// Helper that peeks through INSERT_SUBVECTOR/CONCAT_VECTORS to find
-// if the subvector can be sourced for free.
-static SDValue getSubVectorSrc(SDValue V, unsigned Index, EVT SubVT) {
-  if (V.getOpcode() == ISD::INSERT_SUBVECTOR &&
-      V.getOperand(1).getValueType() == SubVT &&
-      V.getConstantOperandAPInt(2) == Index) {
-    return V.getOperand(1);
+// Scan one wide operand's INSERT_SUBVECTOR chain (optionally rooted at a
+// CONCAT_VECTORS) a single time and fill in OpNo's source slot for the indices
+// we actually want, i.e. those already seeded in Srcs by the extract users.
+// Indices not in Srcs are ignored, so the chain is never recorded wholesale.
+// The outermost definition of an index wins; an insert that is not
+// SubVT-aligned can straddle two slots, so we stop there and leave deeper
+// indices unavailable.
+static void collectSubVectorSrcs(
+    SDValue V, EVT SubVT, unsigned OpNo,
+    SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> &Srcs) {
+  unsigned NumSubElts = SubVT.getVectorMinNumElements();
+  auto record = [&](unsigned Idx, SDValue Sub) {
+    auto It = Srcs.find(Idx);
+    if (It == Srcs.end())
+      return;
+    SDValue &Slot =
+        OpNo == 0 ? std::get<1>(It->second) : std::get<2>(It->second);
+    if (!Slot)
+      Slot = Sub;
+  };
+  while (V.getOpcode() == ISD::INSERT_SUBVECTOR &&
+         V.getOperand(1).getValueType() == SubVT) {
+    uint64_t InsIdx = V.getConstantOperandVal(2);
+    if ((InsIdx % NumSubElts) != 0)
+      return;
+    record(InsIdx, V.getOperand(1));
+    V = V.getOperand(0);
   }
   if (V.getOpcode() == ISD::CONCAT_VECTORS &&
-      V.getOperand(0).getValueType() == SubVT &&
-      (Index % SubVT.getVectorMinNumElements()) == 0) {
-    uint64_t SubIdx = Index / SubVT.getVectorMinNumElements();
-    return V.getOperand(SubIdx);
-  }
-  return SDValue();
-}
-
-static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
-                                              SDValue BinOp, unsigned Index,
-                                              const SDLoc &DL,
+      V.getOperand(0).getValueType() == SubVT)
+    for (unsigned I = 0, E = V.getNumOperands(); I != E; ++I)
+      record(I * NumSubElts, V.getOperand(I));
+}
+
+// Try to narrow a wide vector binop whose result is consumed *only* by
+// extract_subvector nodes that all extract the SAME narrow type. The pattern
+// is:
+//   extract (binop (insert/concat ..., X, Idx), (insert/concat ..., Y, Idx)),
+//   Idx
+// When every extract pulls the same SubVT out of both wide operands for free,
+// we replace the wide binop by one narrow binop per extract, eliminating all of
+// the inserts/extracts and the wide binop in a single combine:
+//   extract ..., Idx --> binop X, Y
+// We seed a map with the wanted extract indices, then scan each wide operand's
+// insert/concat chain exactly once to fill in the per-operand sources, so the
+// chains are never re-walked per extract. N is the extract currently being
+// combined: its narrow binop is returned for the caller to fold in, while the
+// sibling extracts are rewritten here so the wide binop is left with no users.
+static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
                                               SelectionDAG &DAG,
                                               bool LegalOperations) {
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -27201,32 +27231,48 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, EVT SubVT,
   SDValue Bop0 = BinOp.getOperand(0), Bop1 = BinOp.getOperand(1);
   if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType())
     return SDValue();
-  if (!TLI.isOperationLegalOrCustom(BinOpcode, SubVT, LegalOperations))
-    return SDValue();
-
-  SDValue Sub0 = getSubVectorSrc(Bop0, Index, SubVT);
-  SDValue Sub1 = getSubVectorSrc(Bop1, Index, SubVT);
-
-  // TODO: We could handle the case where only 1 operand is being inserted by
-  //       creating an extract of the other operand, but that requires checking
-  //       number of uses and/or costs.
-  if (!Sub0 || !Sub1)
-    return SDValue();
 
-  // Every other user of the wide binop must be an EXTRACT_SUBVECTOR that is
-  // still on the combiner worklist; otherwise the wide binop may remain needed.
+  // This fold only pays off when the wide binop disappears completely, so every
+  // user must be an extract_subvector. Require them all to extract N's type so
+  // a single chain scan serves every extract, and seed the source map by index.
+  EVT SubVT = N->getValueType(0);
+  SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> Extracts;
   for (SDNode *User : BinOp->users()) {
-    if (User == N)
-      continue;
     if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
-        User->getCombinerWorklistIndex() < 0)
+        User->getValueType(0) != SubVT ||
+        (User->getCombinerWorklistIndex() < 0 && User != N))
       return SDValue();
+    Extracts[User->getConstantOperandVal(1)] =
+        std::make_tuple(User, SDValue(), SDValue());
   }
 
-  // We are inserting both operands of the wide binop only to extract back
-  // to the narrow vector size. Eliminate all of the insert/extract:
-  // ext (binop (ins ?, X, Index), (ins ?, Y, Index)), Index --> binop X, Y
-  return DAG.getNode(BinOpcode, DL, SubVT, Sub0, Sub1, BinOp->getFlags());
+  if (!TLI.isOperationLegalOrCustom(BinOpcode, SubVT, LegalOperations))
+    return SDValue();
+
+  // Scan each wide operand's chain once, filling the seeded indices' sources.
+  collectSubVectorSrcs(Bop0, SubVT, /*OpNo=*/0, Extracts);
+  collectSubVectorSrcs(Bop1, SubVT, /*OpNo=*/1, Extracts);
+
+  // Bail unless every wanted index was sourced for free from both operands, so
+  // we commit to rewriting all of the extracts or none.
+  for (auto &[Idx, Ext] : Extracts)
+    if (!std::get<1>(Ext) || !std::get<2>(Ext))
+      return SDValue();
+
+  // Replace each extract with a narrow binop over the matching subvectors:
+  // ext (binop (ins ?, X, Idx), (ins ?, Y, Idx)), Idx --> binop X, Y
+  // Build N's replacement first so node creation order (and thus scheduling)
+  // matches the combiner visiting N directly; rewrite the siblings in place.
+  SDValue Result = SDValue();
+  for (auto &[Idx, Entry] : Extracts) {
+    auto [Ext, Sub0, Sub1] = Entry;
+    SDValue Narrow = DAG.getNode(BinOpcode, SDLoc(Ext), SubVT, Sub0, Sub1,
+                                 BinOp->getFlags());
+    DAG.ReplaceAllUsesOfValueWith(SDValue(Ext, 0), Narrow);
+    if (Ext == N)
+      Result = Narrow;
+  }
+  return Result;
 }
 
 /// If we are extracting a subvector produced by a wide binary operator try
@@ -27238,8 +27284,7 @@ static SDValue narrowExtractedVectorBinOp(SDNode *N, EVT VT, SDValue Src,
   // TODO: Refactor with the caller (visitEXTRACT_SUBVECTOR), so we can share
   // some of these bailouts with other transforms.
 
-  if (SDValue V = narrowInsertExtractVectorBinOp(N, VT, Src, Index, DL, DAG,
-                                                 LegalOperations))
+  if (SDValue V = narrowInsertExtractVectorBinOp(N, Src, DAG, LegalOperations))
     return V;
 
   // We are looking for an optionally bitcasted wide vector binary operator
diff --git a/llvm/test/CodeGen/X86/vector-narrow-binop.ll b/llvm/test/CodeGen/X86/vector-narrow-binop.ll
index ad345213c1472..804f6c10e3ba4 100644
--- a/llvm/test/CodeGen/X86/vector-narrow-binop.ll
+++ b/llvm/test/CodeGen/X86/vector-narrow-binop.ll
@@ -180,8 +180,8 @@ define <4 x double> @fmul_v2f64(<2 x  double> %x, <2 x double> %y) {
 ;
 ; AVX512-LABEL: fmul_v2f64:
 ; AVX512:       # %bb.0:
-; AVX512-NEXT:    vunpckhpd {{.*#+}} xmm2 = xmm0[1],xmm1[1]
-; AVX512-NEXT:    vunpcklpd {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vunpcklpd {{.*#+}} xmm2 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vunpckhpd {{.*#+}} xmm0 = xmm0[1],xmm1[1]
 ; AVX512-NEXT:    vmulpd %xmm0, %xmm0, %xmm0
 ; AVX512-NEXT:    vfmadd231pd {{.*#+}} xmm0 = (xmm2 * xmm2) + xmm0
 ; AVX512-NEXT:    vshufpd {{.*#+}} xmm0 = xmm0[1,0]

>From fcfd4ad969b02e218e0db0e0bf3bf930b0cc4932 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Fri, 12 Jun 2026 17:51:18 +0800
Subject: [PATCH 7/7] add target specific block

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp      | 14 +++++++++++++-
 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp    |  9 +++++++++
 llvm/lib/Target/AArch64/AArch64ISelLowering.h      |  2 ++
 .../CodeGen/RISCV/rvv/musttail-indirect-args.ll    |  4 ++--
 4 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 639ae05c0742c..d7629b75a78c4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27235,13 +27235,16 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
 
   EVT VecVT = BinOp.getValueType();
   SDValue Bop0 = BinOp.getOperand(0), Bop1 = BinOp.getOperand(1);
-  if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType())
+  if (VecVT != Bop0.getValueType() || VecVT != Bop1.getValueType() ||
+      VecVT.isScalableVT())
     return SDValue();
 
   // This fold only pays off when the wide binop disappears completely, so every
   // user must be an extract_subvector. Require them all to extract N's type so
   // a single chain scan serves every extract, and seed the source map by index.
   EVT SubVT = N->getValueType(0);
+  if (VecVT.getSizeInBits() <= SubVT.getSizeInBits())
+    return SDValue();
   SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> Extracts;
   for (SDNode *User : BinOp->users()) {
     if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
@@ -27265,6 +27268,15 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
     if (!std::get<1>(Ext) || !std::get<2>(Ext))
       return SDValue();
 
+  if (TLI.isTypeLegal(VecVT)) {
+    bool AllExtractsCheap = true;
+    for (auto &[Idx, Ext] : Extracts)
+      AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
+    if (AllExtractsCheap &&
+        !TLI.isNarrowingProfitable(BinOp.getNode(), VecVT, SubVT))
+      return SDValue();
+  }
+
   // Replace each extract with a narrow binop over the matching subvectors:
   // ext (binop (ins ?, X, Idx), (ins ?, Y, Idx)), Idx --> binop X, Y
   // Build N's replacement first so node creation order (and thus scheduling)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 57a2d73e00f57..0738f07404af6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -19676,6 +19676,15 @@ bool AArch64TargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
   return (Index == 0 || Index == ResVT.getVectorMinNumElements());
 }
 
+bool AArch64TargetLowering::isNarrowingProfitable(SDNode *N, EVT SrcVT,
+                                                  EVT DestVT) const {
+  // Splitting a wide vector binop into narrower ones removes the wide operand
+  // construction (a concatenation), so prefer narrowing for vectors. Scalar
+  // bit-width narrowing is not generally profitable on AArch64, so keep the
+  // conservative default there.
+  return SrcVT.isVector() && isBinOp(N->getOpcode());
+}
+
 bool AArch64TargetLowering::shouldOptimizeMulOverflowWithZeroHighBits(
     LLVMContext &Context, EVT VT) const {
   if (getTypeAction(Context, VT) != TypeExpandInteger)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 7e4c4e1ba25ff..522d761f0f1cc 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -331,6 +331,8 @@ class AArch64TargetLowering : public TargetLowering {
   bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
                                unsigned Index) const override;
 
+  bool isNarrowingProfitable(SDNode *N, EVT SrcVT, EVT DestVT) const override;
+
   bool shouldFormOverflowOp(unsigned Opcode, EVT VT,
                             bool MathUsed) const override {
     // Using overflow ops for overflow checks only should beneficial on
diff --git a/llvm/test/CodeGen/RISCV/rvv/musttail-indirect-args.ll b/llvm/test/CodeGen/RISCV/rvv/musttail-indirect-args.ll
index 082786f35cb0f..5aa500b018b46 100644
--- a/llvm/test/CodeGen/RISCV/rvv/musttail-indirect-args.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/musttail-indirect-args.ll
@@ -58,9 +58,9 @@ define <vscale x 32 x i32> @caller_musttail_scalable_mixed(<vscale x 32 x i32> %
 ; CHECK-NEXT:    vl8re32.v v0, (a1)
 ; CHECK-NEXT:    vsetvli a2, zero, e32, m8, ta, ma
 ; CHECK-NEXT:    vadd.vv v24, v8, v24
+; CHECK-NEXT:    vadd.vv v0, v16, v0
 ; CHECK-NEXT:    vs8r.v v24, (a0)
-; CHECK-NEXT:    vadd.vv v24, v16, v0
-; CHECK-NEXT:    vs8r.v v24, (a1)
+; CHECK-NEXT:    vs8r.v v0, (a1)
 ; CHECK-NEXT:    tail callee_musttail_scalable
   %s = add <vscale x 32 x i32> %x, %y
   %r = musttail call <vscale x 32 x i32> @callee_musttail_scalable(<vscale x 32 x i32> %x, <vscale x 32 x i32> %s)



More information about the llvm-commits mailing list