[llvm-branch-commits] [llvm] [X86] keep upper-16-bit f32 extractions in XMM for f16/v8i16 (PR #230698)

Emilio Cota via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Oct 12 03:09:08 PDT 2026


https://github.com/cota updated https://github.com/llvm/llvm-project/pull/230698

>From 2cc8bae2867fa59c7f8a4f0f23b79b17f109241d Mon Sep 17 00:00:00 2001
From: Emilio Cota <ecg at google.com>
Date: Fri, 9 Oct 2026 22:05:15 +0000
Subject: [PATCH] [X86] Keep upper-16-bit f32 extractions in XMM for f16/v8i16

Teach combineBitcast and combineVectorInsert to keep this upper-16-bit
f32 extraction in XMM registers rather than bouncing through a GPR.

Depends on PR: https://github.com/llvm/llvm-project/pull/231112
Follow-up PR:  https://github.com/llvm/llvm-project/pull/230557
---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 32 +++++++++++++++++++++
 llvm/test/CodeGen/X86/bfloat.ll         | 37 ++++++-------------------
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6e705d1800a03..62e04e6ea320f 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -47241,6 +47241,22 @@ static SDValue combineBitcast(SDNode *N, SelectionDAG &DAG,
                          DAG.getBitcast(MVT::v8f16, Src.getOperand(0)),
                          DAG.getVectorIdxConstant(0, DL));
     }
+    using namespace SDPatternMatch;
+    SDValue FpOp;
+    if (Subtarget.hasSSE2() && N0.hasOneUse() &&
+        sd_match(Src, m_OneUse(m_Srl(m_OneUse(m_BitCast(m_Value(
+                                         FpOp, m_SpecificVT(MVT::f32)))),
+                                     m_SpecificInt(16)))) &&
+        !ISD::isNormalLoad(FpOp.getNode())) {
+      SDLoc DL(N);
+      SDValue Vec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v4f32, FpOp);
+      Vec = DAG.getBitcast(MVT::v4i32, Vec);
+      Vec = getTargetVShiftByConstNode(X86ISD::VSRLI, DL, MVT::v4i32, Vec, 16,
+                                       DAG);
+      return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT,
+                         DAG.getBitcast(MVT::v8f16, Vec),
+                         DAG.getVectorIdxConstant(0, DL));
+    }
   }
 
   // Since MMX types are special and don't usually play with other vector types,
@@ -52344,6 +52360,22 @@ static SDValue combineVectorInsert(SDNode *N, SelectionDAG &DAG,
       return SDValue(N, 0);
   }
 
+  if (Opcode == X86ISD::PINSRW && Subtarget.hasSSE41()) {
+    using namespace SDPatternMatch;
+    SDValue FpOp;
+    if (sd_match(Scl, m_OneUse(m_Srl(m_OneUse(m_BitCast(m_Value(
+                                         FpOp, m_SpecificVT(MVT::f32)))),
+                                     m_SpecificInt(16)))) &&
+        !ISD::isNormalLoad(FpOp.getNode())) {
+      SDLoc DL(N);
+      SDValue SrcVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v4f32, FpOp);
+      int Mask[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+      Mask[N->getConstantOperandVal(2)] = 9;
+      return DAG.getVectorShuffle(VT, DL, Vec, DAG.getBitcast(VT, SrcVec),
+                                  Mask);
+    }
+  }
+
   // Attempt to combine insertion patterns to a shuffle.
   if (VT.isSimple() && DCI.isAfterLegalizeDAG()) {
     SDValue Op(N, 0);
diff --git a/llvm/test/CodeGen/X86/bfloat.ll b/llvm/test/CodeGen/X86/bfloat.ll
index ec7b190664a62..eb9dcae47910c 100644
--- a/llvm/test/CodeGen/X86/bfloat.ll
+++ b/llvm/test/CodeGen/X86/bfloat.ll
@@ -2717,31 +2717,13 @@ define half @bitcast_f32_hi16(float %f) {
 ;
 ; SSE2-LABEL: bitcast_f32_hi16:
 ; SSE2:       # %bb.0:
-; SSE2-NEXT:    movd %xmm0, %eax
-; SSE2-NEXT:    shrl $16, %eax
-; SSE2-NEXT:    pinsrw $0, %eax, %xmm0
+; SSE2-NEXT:    psrld $16, %xmm0
 ; SSE2-NEXT:    retq
 ;
-; AVX512BF16-LABEL: bitcast_f32_hi16:
-; AVX512BF16:       # %bb.0:
-; AVX512BF16-NEXT:    vmovd %xmm0, %eax
-; AVX512BF16-NEXT:    shrl $16, %eax
-; AVX512BF16-NEXT:    vpinsrw $0, %eax, %xmm0, %xmm0
-; AVX512BF16-NEXT:    retq
-;
-; AVX512FP16-LABEL: bitcast_f32_hi16:
-; AVX512FP16:       # %bb.0:
-; AVX512FP16-NEXT:    vmovd %xmm0, %eax
-; AVX512FP16-NEXT:    shrl $16, %eax
-; AVX512FP16-NEXT:    vmovw %eax, %xmm0
-; AVX512FP16-NEXT:    retq
-;
-; AVXNC-LABEL: bitcast_f32_hi16:
-; AVXNC:       # %bb.0:
-; AVXNC-NEXT:    vmovd %xmm0, %eax
-; AVXNC-NEXT:    shrl $16, %eax
-; AVXNC-NEXT:    vpinsrw $0, %eax, %xmm0, %xmm0
-; AVXNC-NEXT:    retq
+; AVX-LABEL: bitcast_f32_hi16:
+; AVX:       # %bb.0:
+; AVX-NEXT:    vpsrld $16, %xmm0, %xmm0
+; AVX-NEXT:    retq
   %i = bitcast float %f to i32
   %s = lshr i32 %i, 16
   %t = trunc i32 %s to i16
@@ -2764,9 +2746,7 @@ define <8 x i16> @insert_f32_hi16(<8 x i16> %vec, float %f) {
 ;
 ; AVX-LABEL: insert_f32_hi16:
 ; AVX:       # %bb.0:
-; AVX-NEXT:    vmovd %xmm1, %eax
-; AVX-NEXT:    shrl $16, %eax
-; AVX-NEXT:    vpinsrw $1, %eax, %xmm0, %xmm0
+; AVX-NEXT:    vpblendw {{.*#+}} xmm0 = xmm0[0],xmm1[1],xmm0[2,3,4,5,6,7]
 ; AVX-NEXT:    retq
   %i = bitcast float %f to i32
   %s = lshr i32 %i, 16
@@ -2790,9 +2770,8 @@ define <8 x i16> @insert_f32_hi16_lane2(<8 x i16> %vec, float %f) {
 ;
 ; AVX-LABEL: insert_f32_hi16_lane2:
 ; AVX:       # %bb.0:
-; AVX-NEXT:    vmovd %xmm1, %eax
-; AVX-NEXT:    shrl $16, %eax
-; AVX-NEXT:    vpinsrw $2, %eax, %xmm0, %xmm0
+; AVX-NEXT:    vpmovzxwd {{.*#+}} xmm1 = xmm1[0],zero,xmm1[1],zero,xmm1[2],zero,xmm1[3],zero
+; AVX-NEXT:    vpblendw {{.*#+}} xmm0 = xmm0[0,1],xmm1[2],xmm0[3,4,5,6,7]
 ; AVX-NEXT:    retq
   %i = bitcast float %f to i32
   %s = lshr i32 %i, 16



More information about the llvm-branch-commits mailing list