[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
Sun Jul 5 16:57:40 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 01/15] 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 02/15] 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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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)
>From 463e240e0bd9598d67165126f9d8cb501d0b9b5f Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 15 Jun 2026 08:46:37 +0800
Subject: [PATCH 08/15] fix tests
---
llvm/test/CodeGen/AMDGPU/maximumnum.ll | 4 ++--
llvm/test/CodeGen/AMDGPU/minimumnum.ll | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/maximumnum.ll b/llvm/test/CodeGen/AMDGPU/maximumnum.ll
index 9b7c8a4e3f314..210a640942b97 100644
--- a/llvm/test/CodeGen/AMDGPU/maximumnum.ll
+++ b/llvm/test/CodeGen/AMDGPU/maximumnum.ll
@@ -5133,11 +5133,11 @@ define <3 x half> @v_maximumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
; GFX1251-SDAG: ; %bb.0:
; GFX1251-SDAG-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX1251-SDAG-NEXT: s_wait_kmcnt 0x0
-; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v3, v3, v3
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v2, v2, v2
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v0, v0, v0
+; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v3, v3, v3
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v1, v1, v1
-; GFX1251-SDAG-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX1251-SDAG-NEXT: s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v0, v0, v2
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v1, v1, v3
; GFX1251-SDAG-NEXT: s_set_pc_i64 s[30:31]
diff --git a/llvm/test/CodeGen/AMDGPU/minimumnum.ll b/llvm/test/CodeGen/AMDGPU/minimumnum.ll
index e4107760310be..33c8662a2153e 100644
--- a/llvm/test/CodeGen/AMDGPU/minimumnum.ll
+++ b/llvm/test/CodeGen/AMDGPU/minimumnum.ll
@@ -4883,11 +4883,11 @@ define <3 x half> @v_minimumnum_v3f16(<3 x half> %x, <3 x half> %y) #1 {
; GFX1251-SDAG: ; %bb.0:
; GFX1251-SDAG-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX1251-SDAG-NEXT: s_wait_kmcnt 0x0
-; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v3, v3, v3
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v2, v2, v2
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v0, v0, v0
+; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v3, v3, v3
; GFX1251-SDAG-NEXT: v_pk_max_num_f16 v1, v1, v1
-; GFX1251-SDAG-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX1251-SDAG-NEXT: s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
; GFX1251-SDAG-NEXT: v_pk_min_num_f16 v0, v0, v2
; GFX1251-SDAG-NEXT: v_pk_min_num_f16 v1, v1, v3
; GFX1251-SDAG-NEXT: s_set_pc_i64 s[30:31]
>From 5a654d88fa9fd3e3d56e1eb9ce2ee5b8aaf9238a Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Wed, 17 Jun 2026 09:55:11 +0800
Subject: [PATCH 09/15] fix test
---
llvm/test/CodeGen/AMDGPU/usubsat.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/usubsat.ll b/llvm/test/CodeGen/AMDGPU/usubsat.ll
index 7b0a019a710f0..4b8f7cc180eb6 100644
--- a/llvm/test/CodeGen/AMDGPU/usubsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/usubsat.ll
@@ -683,10 +683,10 @@ define <3 x i16> @s_usubsat_v3i16(<3 x i16> inreg %lhs, <3 x i16> inreg %rhs) {
; GFX9-LABEL: s_usubsat_v3i16:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: v_mov_b32_e32 v0, s19
-; GFX9-NEXT: v_pk_sub_u16 v1, s17, v0 clamp
; GFX9-NEXT: v_mov_b32_e32 v0, s18
+; GFX9-NEXT: v_mov_b32_e32 v1, s19
; GFX9-NEXT: v_pk_sub_u16 v0, s16, v0 clamp
+; GFX9-NEXT: v_pk_sub_u16 v1, s17, v1 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10-LABEL: s_usubsat_v3i16:
>From 9b8a71d90b8c324b608e14a23278816005d09375 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Mon, 22 Jun 2026 16:15:04 +0800
Subject: [PATCH 10/15] fix test case
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 75 +++++++++++++------
1 file changed, 52 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 83ddf78dee0e6..5b0a1dca212d2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27235,11 +27235,8 @@ static void collectSubVectorSrcs(
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);
+ std::tuple<SDNode *, SDValue, SDValue> &Ext = Srcs[Idx];
+ SDValue &Slot = OpNo == 0 ? std::get<1>(Ext) : std::get<2>(Ext);
if (!Slot)
Slot = Sub;
};
@@ -27291,33 +27288,63 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
EVT SubVT = N->getValueType(0);
if (VecVT.getSizeInBits() <= SubVT.getSizeInBits())
return SDValue();
+
SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> Extracts;
+ // Scan each wide operand's chain once, filling the seeded indices' sources.
+ collectSubVectorSrcs(Bop0, SubVT, /*OpNo=*/0, Extracts);
+ collectSubVectorSrcs(Bop1, SubVT, /*OpNo=*/1, Extracts);
+
+ bool HasNonZeroExt = false;
+ bool HasNonExtUser = false;
for (SDNode *User : BinOp->users()) {
- if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
- User->getValueType(0) != SubVT ||
+ if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR) {
+ HasNonExtUser = true;
+ continue;
+ }
+ if (User->getValueType(0) != SubVT ||
(User->getCombinerWorklistIndex() < 0 && User != N))
return SDValue();
- Extracts[User->getConstantOperandVal(1)] =
- std::make_tuple(User, SDValue(), SDValue());
+ unsigned Idx = User->getConstantOperandVal(1);
+ auto It = Extracts.find(Idx);
+ if (It == Extracts.end() || !std::get<1>(It->second) ||
+ !std::get<2>(It->second))
+ return SDValue();
+ SDNode *&ExtSubVec = std::get<0>(It->second);
+ if (!ExtSubVec) {
+ ExtSubVec = User;
+ if (Idx != 0)
+ HasNonZeroExt = true;
+ }
}
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))
+ // Narrow for [SubVT, 0/undef,...,0/undef]: when the wide binop also has a
+ // non-extract user it survives, so narrowing only pays off if it folds for
+ // free to concat(narrow binop, 0/undef, ...). That holds when the sole
+ // extract is lane 0 (HasNonZeroExt rejects multi-real-lane cases such as
+ // [a,b,0,0,c,d]) and every other lane is 0/undef in both operands; otherwise
+ // a lane carries real data the wide binop must still compute. `V &&` keeps
+ // IsZeroOrUndef null-safe for lanes that were never sourced.
+ auto IsZeroOrUndef = [](SDValue V) {
+ return V && (V.isUndef() || ISD::isBuildVectorAllZeros(V.getNode()) ||
+ isNullOrNullSplat(V));
+ };
+ if (HasNonExtUser) {
+ if (HasNonZeroExt)
return SDValue();
+ for (auto &[Idx, Entry] : Extracts)
+ if (Idx != 0 && (!IsZeroOrUndef(std::get<1>(Entry)) ||
+ !IsZeroOrUndef(std::get<2>(Entry))))
+ return SDValue();
+ }
if (TLI.isTypeLegal(VecVT)) {
bool AllExtractsCheap = true;
for (auto &[Idx, Ext] : Extracts)
- AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
+ if (std::get<0>(Ext)) // Only lanes actually consumed by an extract.
+ AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
if (AllExtractsCheap &&
!TLI.isNarrowingProfitable(BinOp.getNode(), VecVT, SubVT))
return SDValue();
@@ -27330,11 +27357,13 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
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;
+ if (Ext) {
+ 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;
}
>From 8e535fd4ebfc91340eb34de4a2342a3a12b817d0 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 30 Jun 2026 12:27:51 +0800
Subject: [PATCH 11/15] fix comments
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 97 +++++++++++--------
1 file changed, 56 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 366daf643cdd8..a0b7866f311f8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27241,19 +27241,22 @@ SDValue DAGCombiner::visitVECTOR_INTERLEAVE(SDNode *N) {
}
// 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.
+// CONCAT_VECTORS) a single time and fill in OpNo's source for each SubVT-sized
+// slot. Slots are indexed by their subvector position, so the chain is never
+// recorded wholesale. Each slot is a tuple of the extract_subvector user (if
+// any) and the matching subvector source from each wide operand; a slot whose
+// two sources are both null was never seen on either chain (i.e. it is undef).
+// The outermost definition of a slot wins; an insert that is not SubVT-aligned
+// can straddle two slots, so we stop there and leave deeper slots unavailable.
static void collectSubVectorSrcs(
SDValue V, EVT SubVT, unsigned OpNo,
- SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> &Srcs) {
+ MutableArrayRef<std::tuple<SDNode *, SDValue, SDValue>> Slots) {
unsigned NumSubElts = SubVT.getVectorMinNumElements();
- auto record = [&](unsigned Idx, SDValue Sub) {
- std::tuple<SDNode *, SDValue, SDValue> &Ext = Srcs[Idx];
- SDValue &Slot = OpNo == 0 ? std::get<1>(Ext) : std::get<2>(Ext);
+ auto record = [&](unsigned Part, SDValue Sub) {
+ if (Part >= Slots.size())
+ return;
+ SDValue &Slot =
+ OpNo == 0 ? std::get<1>(Slots[Part]) : std::get<2>(Slots[Part]);
if (!Slot)
Slot = Sub;
};
@@ -27262,13 +27265,13 @@ static void collectSubVectorSrcs(
uint64_t InsIdx = V.getConstantOperandVal(2);
if ((InsIdx % NumSubElts) != 0)
return;
- record(InsIdx, V.getOperand(1));
+ record(InsIdx / NumSubElts, V.getOperand(1));
V = V.getOperand(0);
}
if (V.getOpcode() == ISD::CONCAT_VECTORS &&
V.getOperand(0).getValueType() == SubVT)
for (unsigned I = 0, E = V.getNumOperands(); I != E; ++I)
- record(I * NumSubElts, V.getOperand(I));
+ record(I, V.getOperand(I));
}
// Try to narrow a wide vector binop whose result is consumed *only* by
@@ -27280,11 +27283,12 @@ static void collectSubVectorSrcs(
// 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.
+// We use a flat per-slot table indexed by subvector position, 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) {
@@ -27301,15 +27305,22 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
// 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.
+ // a single chain scan serves every extract.
EVT SubVT = N->getValueType(0);
if (VecVT.getSizeInBits() <= SubVT.getSizeInBits())
return SDValue();
- SmallMapVector<unsigned, std::tuple<SDNode *, SDValue, SDValue>, 4> Extracts;
- // Scan each wide operand's chain once, filling the seeded indices' sources.
- collectSubVectorSrcs(Bop0, SubVT, /*OpNo=*/0, Extracts);
- collectSubVectorSrcs(Bop1, SubVT, /*OpNo=*/1, Extracts);
+ if (!TLI.isOperationLegalOrCustom(BinOpcode, SubVT, LegalOperations))
+ return SDValue();
+
+ // The wide binop splits into a small, dense set of SubVT-sized slots, so a
+ // flat table indexed by subvector position is all we need.
+ unsigned NumSubElts = SubVT.getVectorMinNumElements();
+ unsigned NumParts = VecVT.getVectorMinNumElements() / NumSubElts;
+ SmallVector<std::tuple<SDNode *, SDValue, SDValue>, 4> Slots(NumParts);
+ // Scan each wide operand's chain once, filling each slot's source.
+ collectSubVectorSrcs(Bop0, SubVT, /*OpNo=*/0, Slots);
+ collectSubVectorSrcs(Bop1, SubVT, /*OpNo=*/1, Slots);
bool HasNonZeroExt = false;
bool HasNonExtUser = false;
@@ -27322,11 +27333,12 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
(User->getCombinerWorklistIndex() < 0 && User != N))
return SDValue();
unsigned Idx = User->getConstantOperandVal(1);
- auto It = Extracts.find(Idx);
- if (It == Extracts.end() || !std::get<1>(It->second) ||
- !std::get<2>(It->second))
+ if (Idx % NumSubElts != 0 || Idx / NumSubElts >= NumParts)
+ return SDValue();
+ auto &Slot = Slots[Idx / NumSubElts];
+ if (!std::get<1>(Slot) || !std::get<2>(Slot))
return SDValue();
- SDNode *&ExtSubVec = std::get<0>(It->second);
+ SDNode *&ExtSubVec = std::get<0>(Slot);
if (!ExtSubVec) {
ExtSubVec = User;
if (Idx != 0)
@@ -27334,34 +27346,37 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
}
}
- if (!TLI.isOperationLegalOrCustom(BinOpcode, SubVT, LegalOperations))
- return SDValue();
-
// Narrow for [SubVT, 0/undef,...,0/undef]: when the wide binop also has a
// non-extract user it survives, so narrowing only pays off if it folds for
// free to concat(narrow binop, 0/undef, ...). That holds when the sole
// extract is lane 0 (HasNonZeroExt rejects multi-real-lane cases such as
// [a,b,0,0,c,d]) and every other lane is 0/undef in both operands; otherwise
- // a lane carries real data the wide binop must still compute. `V &&` keeps
- // IsZeroOrUndef null-safe for lanes that were never sourced.
+ // a lane carries real data the wide binop must still compute. A slot with
+ // both sources null was never sourced (i.e. undef) and is skipped; a slot
+ // sourced on only one operand has a null source there which is not provably
+ // 0/undef, so `V &&` makes IsZeroOrUndef reject it.
auto IsZeroOrUndef = [](SDValue V) {
- return V && (V.isUndef() || ISD::isBuildVectorAllZeros(V.getNode()) ||
- isNullOrNullSplat(V));
+ return V && (V.isUndef() || isNullOrNullSplat(V, /*AllowUndefs=*/true));
};
if (HasNonExtUser) {
if (HasNonZeroExt)
return SDValue();
- for (auto &[Idx, Entry] : Extracts)
- if (Idx != 0 && (!IsZeroOrUndef(std::get<1>(Entry)) ||
- !IsZeroOrUndef(std::get<2>(Entry))))
+ for (unsigned Part = 1; Part < NumParts; ++Part) {
+ auto &Slot = Slots[Part];
+ if (!std::get<1>(Slot) && !std::get<2>(Slot))
+ continue;
+ if (!IsZeroOrUndef(std::get<1>(Slot)) ||
+ !IsZeroOrUndef(std::get<2>(Slot)))
return SDValue();
+ }
}
if (TLI.isTypeLegal(VecVT)) {
bool AllExtractsCheap = true;
- for (auto &[Idx, Ext] : Extracts)
- if (std::get<0>(Ext)) // Only lanes actually consumed by an extract.
- AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
+ for (unsigned Part = 0; Part < NumParts; ++Part)
+ if (std::get<0>(Slots[Part])) // Only lanes actually consumed by extract.
+ AllExtractsCheap &=
+ TLI.isExtractSubvectorCheap(SubVT, VecVT, Part * NumSubElts);
if (AllExtractsCheap &&
!TLI.isNarrowingProfitable(BinOp.getNode(), VecVT, SubVT))
return SDValue();
@@ -27372,8 +27387,8 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
// 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;
+ for (auto &Slot : Slots) {
+ auto [Ext, Sub0, Sub1] = Slot;
if (Ext) {
SDValue Narrow = DAG.getNode(BinOpcode, SDLoc(Ext), SubVT, Sub0, Sub1,
BinOp->getFlags());
>From a47f976ebb911cb117968b9ace7115225f6ad655 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 30 Jun 2026 15:05:54 +0800
Subject: [PATCH 12/15] fix comments
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 22 ++++++++-----------
.../extract-subvector-binop-wide-use.ll | 2 +-
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index c114932618dea..8cb0ee151eece 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27326,6 +27326,7 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
bool HasNonZeroExt = false;
bool HasNonExtUser = false;
+ bool AllExtractsCheap = true;
for (SDNode *User : BinOp->users()) {
if (User->getOpcode() != ISD::EXTRACT_SUBVECTOR) {
HasNonExtUser = true;
@@ -27343,11 +27344,18 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
SDNode *&ExtSubVec = std::get<0>(Slot);
if (!ExtSubVec) {
ExtSubVec = User;
+ AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
if (Idx != 0)
HasNonZeroExt = true;
+ } else {
+ llvm_unreachable("Duplicate extract subvector");
}
}
+ if (TLI.isTypeLegal(VecVT) && AllExtractsCheap &&
+ !TLI.isNarrowingProfitable(BinOp.getNode(), VecVT, SubVT))
+ return SDValue();
+
// Narrow for [SubVT, 0/undef,...,0/undef]: when the wide binop also has a
// non-extract user it survives, so narrowing only pays off if it folds for
// free to concat(narrow binop, 0/undef, ...). That holds when the sole
@@ -27373,24 +27381,12 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
}
}
- if (TLI.isTypeLegal(VecVT)) {
- bool AllExtractsCheap = true;
- for (unsigned Part = 0; Part < NumParts; ++Part)
- if (std::get<0>(Slots[Part])) // Only lanes actually consumed by extract.
- AllExtractsCheap &=
- TLI.isExtractSubvectorCheap(SubVT, VecVT, Part * NumSubElts);
- 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)
// matches the combiner visiting N directly; rewrite the siblings in place.
SDValue Result = SDValue();
- for (auto &Slot : Slots) {
- auto [Ext, Sub0, Sub1] = Slot;
+ for (auto [Ext, Sub0, Sub1] : Slots) {
if (Ext) {
SDValue Narrow = DAG.getNode(BinOpcode, SDLoc(Ext), SubVT, Sub0, Sub1,
BinOp->getFlags());
diff --git a/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
index c4dcf7c4405b3..b97e0891b84d4 100644
--- a/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
+++ b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; 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) {
>From 3b9a88c67029b7b553e0829c1ef1c8ec5ffed75b Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Tue, 30 Jun 2026 17:00:43 +0800
Subject: [PATCH 13/15] fix comments
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 8cb0ee151eece..3c44342801446 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27338,10 +27338,9 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
unsigned Idx = User->getConstantOperandVal(1);
if (Idx % NumSubElts != 0 || Idx / NumSubElts >= NumParts)
return SDValue();
- auto &Slot = Slots[Idx / NumSubElts];
- if (!std::get<1>(Slot) || !std::get<2>(Slot))
+ auto &[ExtSubVec, Sub0, Sub1] = Slots[Idx / NumSubElts];
+ if (!Sub0 || !Sub1)
return SDValue();
- SDNode *&ExtSubVec = std::get<0>(Slot);
if (!ExtSubVec) {
ExtSubVec = User;
AllExtractsCheap &= TLI.isExtractSubvectorCheap(SubVT, VecVT, Idx);
@@ -27371,12 +27370,10 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
if (HasNonExtUser) {
if (HasNonZeroExt)
return SDValue();
- for (unsigned Part = 1; Part < NumParts; ++Part) {
- auto &Slot = Slots[Part];
- if (!std::get<1>(Slot) && !std::get<2>(Slot))
+ for (auto &[Ext, Sub0, Sub1] : drop_begin(Slots)) {
+ if (!Sub0 && !Sub1)
continue;
- if (!IsZeroOrUndef(std::get<1>(Slot)) ||
- !IsZeroOrUndef(std::get<2>(Slot)))
+ if (!IsZeroOrUndef(Sub0) || !IsZeroOrUndef(Sub1))
return SDValue();
}
}
>From 73be51e68ea702bc6515887f80dac838a6727a7b Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 2 Jul 2026 12:02:29 +0800
Subject: [PATCH 14/15] fix comments
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 25 ++++++++++++-------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 3c44342801446..0f4e85095d7cd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -27262,6 +27262,13 @@ static void collectSubVectorSrcs(
if (!Slot)
Slot = Sub;
};
+ if (V.getOpcode() == ISD::CONCAT_VECTORS &&
+ V.getOperand(0).getValueType() == SubVT) {
+ for (unsigned I = 0, E = V.getNumOperands(); I != E; ++I)
+ record(I, V.getOperand(I));
+ return;
+ }
+
while (V.getOpcode() == ISD::INSERT_SUBVECTOR &&
V.getOperand(1).getValueType() == SubVT) {
uint64_t InsIdx = V.getConstantOperandVal(2);
@@ -27270,17 +27277,19 @@ static void collectSubVectorSrcs(
record(InsIdx / NumSubElts, V.getOperand(1));
V = V.getOperand(0);
}
- if (V.getOpcode() == ISD::CONCAT_VECTORS &&
- V.getOperand(0).getValueType() == SubVT)
- for (unsigned I = 0, E = V.getNumOperands(); I != E; ++I)
- record(I, 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_subvector nodes that all extract the SAME narrow type SubVT. The
+// pattern, for each extract at index Idx, is:
// extract (binop (insert/concat ..., X, Idx), (insert/concat ..., Y, Idx)),
// Idx
+// Within one such match the two inserts and the extract share the same Idx, and
+// across the different extracts the indices are subvector-aligned and strided
+// by the subvector element count: Idx is a multiple of
+// SubVT.getVectorNumElements() (0, NumSubElts, 2*NumSubElts, ...), so each
+// extract pulls out a distinct, non-overlapping SubVT-sized slot.
+// Overlapping/unaligned indices (e.g. extract lanes 0-1 then 1-2) are rejected.
// 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:
@@ -27371,8 +27380,6 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
if (HasNonZeroExt)
return SDValue();
for (auto &[Ext, Sub0, Sub1] : drop_begin(Slots)) {
- if (!Sub0 && !Sub1)
- continue;
if (!IsZeroOrUndef(Sub0) || !IsZeroOrUndef(Sub1))
return SDValue();
}
@@ -27382,7 +27389,7 @@ static SDValue narrowInsertExtractVectorBinOp(SDNode *N, SDValue BinOp,
// 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();
+ SDValue Result;
for (auto [Ext, Sub0, Sub1] : Slots) {
if (Ext) {
SDValue Narrow = DAG.getNode(BinOpcode, SDLoc(Ext), SubVT, Sub0, Sub1,
>From 71785cadfc9c4e7e73421c46f7829a59041207e9 Mon Sep 17 00:00:00 2001
From: shore <372660931 at qq.com>
Date: Thu, 2 Jul 2026 12:07:20 +0800
Subject: [PATCH 15/15] fix comments
---
.../extract-subvector-binop-wide-use.ll | 53 +++++++++++++++++--
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
index b97e0891b84d4..6e690238c7007 100644
--- a/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
+++ b/llvm/test/CodeGen/AMDGPU/extract-subvector-binop-wide-use.ll
@@ -1,9 +1,56 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck --check-prefix=GFX9 %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1030 < %s | FileCheck --check-prefix=GFX10 %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 < %s | FileCheck --check-prefix=GFX11 %s
; 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) {
+; GFX9-LABEL: insert_extract_and_inreg_v4i32:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_and_b32 s4, s19, s21
+; GFX9-NEXT: s_and_b32 s5, s18, s20
+; GFX9-NEXT: v_mov_b32_e32 v0, s5
+; GFX9-NEXT: v_mov_b32_e32 v1, s4
+; GFX9-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-NEXT: global_store_dwordx2 v2, v[0:1], s[16:17]
+; GFX9-NEXT: v_mov_b32_e32 v0, 0
+; GFX9-NEXT: v_mov_b32_e32 v1, 0
+; GFX9-NEXT: v_mov_b32_e32 v2, s5
+; GFX9-NEXT: v_mov_b32_e32 v3, s4
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: insert_extract_and_inreg_v4i32:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: s_and_b32 s4, s18, s20
+; GFX10-NEXT: s_and_b32 s5, s19, s21
+; GFX10-NEXT: v_mov_b32_e32 v0, s4
+; GFX10-NEXT: v_mov_b32_e32 v1, s5
+; GFX10-NEXT: v_mov_b32_e32 v2, 0
+; GFX10-NEXT: v_mov_b32_e32 v3, s5
+; GFX10-NEXT: global_store_dwordx2 v2, v[0:1], s[16:17]
+; GFX10-NEXT: v_mov_b32_e32 v0, 0
+; GFX10-NEXT: v_mov_b32_e32 v1, 0
+; GFX10-NEXT: v_mov_b32_e32 v2, s4
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: insert_extract_and_inreg_v4i32:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: s_and_b32 s2, s2, s16
+; GFX11-NEXT: s_and_b32 s3, s3, s17
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT: v_dual_mov_b32 v0, s2 :: v_dual_mov_b32 v1, s3
+; GFX11-NEXT: v_dual_mov_b32 v2, 0 :: v_dual_mov_b32 v3, s3
+; GFX11-NEXT: global_store_b64 v2, v[0:1], s[0:1]
+; GFX11-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, 0
+; GFX11-NEXT: v_mov_b32_e32 v2, s2
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX1250-LABEL: insert_extract_and_inreg_v4i32:
-; GFX1250: ; %bb.0: ; %entry
+; GFX1250: ; %bb.0:
; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX1250-NEXT: s_wait_kmcnt 0x0
; GFX1250-NEXT: s_and_b32 s2, s2, s16
@@ -16,7 +63,6 @@ define <4 x i32> @insert_extract_and_inreg_v4i32(ptr addrspace(1) inreg %out_sub
; 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
@@ -24,6 +70,3 @@ entry:
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)
More information about the llvm-commits
mailing list