[llvm] [X86] Optimize USUBSAT <N x i64> to vpsubusb (PR #196122)
Tharun V K via llvm-commits
llvm-commits at lists.llvm.org
Wed May 6 10:17:58 PDT 2026
https://github.com/tharunvk created https://github.com/llvm/llvm-project/pull/196122
This fix implements a targeted optimization for llvm.usub.sat on x86 AVX-512 targets. When the operands of a vector saturating subtraction are known to fit within the lower 8 bits (e.g., after a zext(trunc(x)) or an and v, 255 pattern), we can narrow the operation from 64-bit (or 32/16-bit) lanes down to 8-bit lanes.
Fixes https://github.com/llvm/llvm-project/issues/195462
>From bd5c78fc5c99332d3dba2e56f03f0ed4a2bb9f4f Mon Sep 17 00:00:00 2001
From: Tharun V K <tharunms98 at gmail.com>
Date: Wed, 6 May 2026 22:35:06 +0530
Subject: [PATCH] [X86] Optimize USUBSAT <N x i64> to vpsubusb
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 56 +++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 5a1171b2b4ee6..353d74737b197 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -29723,6 +29723,57 @@ static SDValue lowerAddSub(SDValue Op, SelectionDAG &DAG,
return splitVectorIntBinary(Op, DAG, DL);
}
+static SDValue lowerUSUBSATTo8Bit(SDValue Op, SelectionDAG &DAG) {
+ EVT VT = Op.getValueType();
+
+ if (!VT.isVector() || VT.getScalarSizeInBits() <= 8)
+ return SDValue();
+
+ SDValue N0 = Op.getOperand(0);
+ SDValue N1 = Op.getOperand(1);
+
+ if (!ISD::isBuildVectorOfConstantSDNodes(N1.getNode()))
+ return SDValue();
+
+ unsigned ScalarSize = VT.getScalarSizeInBits();
+ unsigned RequiredZeros = ScalarSize - 8;
+
+ KnownBits Known0 = DAG.computeKnownBits(N0);
+ if (Known0.countMinLeadingZeros() < RequiredZeros)
+ return SDValue();
+
+ KnownBits Known1 = DAG.computeKnownBits(N1);
+ if (Known1.countMinLeadingZeros() < RequiredZeros)
+ return SDValue();
+
+ SDLoc DL(Op);
+ EVT ByteVT =
+ EVT::getVectorVT(*DAG.getContext(), MVT::i8, VT.getSizeInBits() / 8);
+ EVT ByteScalarVT = ByteVT.getScalarType();
+
+ SmallVector<SDValue, 64> NewConsts;
+ unsigned NumElts = VT.getVectorNumElements();
+ unsigned BytesPerElt = ScalarSize / 8;
+
+ for (unsigned i = 0; i < NumElts; ++i) {
+ auto *CNode = cast<ConstantSDNode>(N1.getOperand(i));
+ uint64_t Val = CNode->getZExtValue();
+
+ NewConsts.push_back(DAG.getConstant(Val & 0xFF, DL, ByteScalarVT));
+
+ for (unsigned j = 1; j < BytesPerElt; ++j) {
+ NewConsts.push_back(DAG.getConstant(0xFF, DL, ByteScalarVT));
+ }
+ }
+
+ SDValue NewN1 = DAG.getBuildVector(ByteVT, DL, NewConsts);
+ SDValue BitcastN0 = DAG.getBitcast(ByteVT, N0);
+
+ SDValue Sub = DAG.getNode(ISD::USUBSAT, DL, ByteVT, BitcastN0, NewN1);
+
+ return DAG.getBitcast(VT, Sub);
+}
+
static SDValue LowerADDSAT_SUBSAT(SDValue Op, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
MVT VT = Op.getSimpleValueType();
@@ -29730,6 +29781,11 @@ static SDValue LowerADDSAT_SUBSAT(SDValue Op, SelectionDAG &DAG,
unsigned Opcode = Op.getOpcode();
SDLoc DL(Op);
+ if (Opcode == ISD::USUBSAT && Op.getValueType().isVector()) {
+ if (SDValue Res = lowerUSUBSATTo8Bit(Op, DAG))
+ return Res;
+ }
+
if (VT == MVT::v32i16 || VT == MVT::v64i8 ||
(VT.is256BitVector() && !Subtarget.hasInt256())) {
assert(Op.getSimpleValueType().isInteger() &&
More information about the llvm-commits
mailing list