[llvm] [SelectionDAG] Avoid unsafe scalarization of widened rotate extracts (PR #221165)

Oscar Priego via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 02:21:45 PDT 2026


https://github.com/Opriego updated https://github.com/llvm/llvm-project/pull/221165

>From 1b13d9f55d9464d0cc47aa95feff906d33054ac1 Mon Sep 17 00:00:00 2001
From: Oscar Priego Verdugo <oscar.priegov at gmail.com>
Date: Fri, 4 Sep 2026 02:05:47 -0600
Subject: [PATCH] [SelectionDAG] Avoid unsafe scalarization of widened extract
 binops

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 34 ++++++++++++++-----
 .../RISCV/rvv/extract-binop-widened.ll        | 26 ++++++++++++++
 2 files changed, 51 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/rvv/extract-binop-widened.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index e08eaf1ba81d4..b8ae9b8971545 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -25580,17 +25580,28 @@ static SDValue scalarizeExtractedBinOp(SDNode *ExtElt, SelectionDAG &DAG,
   SDValue Index = ExtElt->getOperand(1);
   auto *IndexC = dyn_cast<ConstantSDNode>(Index);
   unsigned Opc = Vec.getOpcode();
-  if (!IndexC || !Vec.hasOneUse() || (!TLI.isBinOp(Opc) && Opc != ISD::SETCC) ||
+  bool IsBinOp = TLI.isBinOp(Opc);
+  if (!IndexC || !Vec.hasOneUse() || (!IsBinOp && Opc != ISD::SETCC) ||
       Vec->getNumValues() != 1)
     return SDValue();
 
-  // Targets may want to avoid this to prevent an expensive register transfer.
-  if (!TLI.shouldScalarizeBinop(Vec))
+  EVT ResVT = ExtElt->getValueType(0);
+  EVT EltVT = Vec.getValueType().getVectorElementType();
+
+  if (Opc == ISD::SETCC && (ResVT != EltVT || LegalTypes))
     return SDValue();
 
-  EVT ResVT = ExtElt->getValueType(0);
-  if (Opc == ISD::SETCC &&
-      (ResVT != Vec.getValueType().getVectorElementType() || LegalTypes))
+  // If EXTRACT_VECTOR_ELT was promoted, rebuilding the binop in the promoted
+  // type can change operations whose semantics depend on type width. Keep the
+  // scalar binop in the vector element type when it is valid to introduce that
+  // type here.
+  bool UseEltVT = IsBinOp && ResVT != EltVT;
+  if (UseEltVT && (!ResVT.isInteger() || !EltVT.isInteger() ||
+                   (LegalTypes && !TLI.isTypeLegal(EltVT))))
+    return SDValue();
+
+  // Targets may want to avoid this to prevent an expensive register transfer.
+  if (!TLI.shouldScalarizeBinop(Vec))
     return SDValue();
 
   // Extracting an element of a vector constant is constant-folded, so this
@@ -25629,9 +25640,14 @@ static SDValue scalarizeExtractedBinOp(SDNode *ExtElt, SelectionDAG &DAG,
     }
     return NewVal;
   }
-  Op0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ResVT, Op0, Index);
-  Op1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ResVT, Op1, Index);
-  return DAG.getNode(Opc, DL, ResVT, Op0, Op1);
+
+  EVT ScalarVT = UseEltVT ? EltVT : ResVT;
+  Op0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ScalarVT, Op0, Index);
+  Op1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ScalarVT, Op1, Index);
+  SDValue BinOp = DAG.getNode(Opc, DL, ScalarVT, Op0, Op1);
+  if (ScalarVT == ResVT)
+    return BinOp;
+  return DAG.getAnyExtOrTrunc(BinOp, DL, ResVT);
 }
 
 // Given a ISD::EXTRACT_VECTOR_ELT, which is a glorified bit sequence extract,
diff --git a/llvm/test/CodeGen/RISCV/rvv/extract-binop-widened.ll b/llvm/test/CodeGen/RISCV/rvv/extract-binop-widened.ll
new file mode 100644
index 0000000000000..96471682004d2
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/extract-binop-widened.ll
@@ -0,0 +1,26 @@
+; RUN: llc -mtriple=riscv64 -mattr=+v < %s | FileCheck %s
+
+define i64 @rotl_extract_widened() {
+; CHECK-LABEL: rotl_extract_widened:
+; CHECK:       lui a0, 15
+; CHECK-NEXT:  addi a0, a0, -106
+; CHECK-NEXT:  ret
+entry:
+  %vec.zero = insertelement <2 x i16> zeroinitializer, i16 0, i32 0
+  %vec.const = xor <2 x i16> %vec.zero, <i16 -7273, i16 -10240>
+  %vec.shifted = call <2 x i16> @llvm.fshl.v2i16(
+      <2 x i16> %vec.const, <2 x i16> %vec.const,
+      <2 x i16> <i16 0, i16 12>)
+
+  %a = extractelement <2 x i16> %vec.shifted, i32 0
+  %az = zext i16 %a to i64
+  %ax = xor i64 %az, 1
+
+  %b = extractelement <2 x i16> %vec.shifted, i32 1
+  %bz = zext i16 %b to i64
+
+  %r = or i64 %ax, %bz
+  ret i64 %r
+}
+
+declare <2 x i16> @llvm.fshl.v2i16(<2 x i16>, <2 x i16>, <2 x i16>)



More information about the llvm-commits mailing list