[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