[llvm] [DAGCombiner] Fix divide-by-zero in visitSUBSAT when LHS is known-zero (PR #218284)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 13:06:15 PDT 2026


https://github.com/sipher-01 created https://github.com/llvm/llvm-project/pull/218284

Fixes a crash introduced by #206592.

When the LHS of `usub.sat` is a known-zero value, `ActiveBits` is 0 and `NarrowBits` starts at 0, causing a divide-by-zero via `ActiveBits % NarrowBits` in `visitSUBSAT`.

Guard the loop with `NarrowBits != 0` to skip the narrowing optimization in this case. Other folds handle the known-zero
case correctly.

A regression test has been added to `usubsat-narrow.ll` using a known-zero LHS (`xor v, v`) to prevent future regressions.

Reported by: @Benjins in #217964

>From 9c872810d3af31a4fc1c459e5f855c47a0452b7c Mon Sep 17 00:00:00 2001
From: Sipher <sourav2003singhkatoch at gmail.com>
Date: Mon, 24 Aug 2026 01:14:43 +0530
Subject: [PATCH] [DAGCombiner] Fix divide-by-zero in visitSUBSAT for
 known-zero LHS

When the LHS of usub.sat is a known-zero value, ActiveBits is 0 and
NarrowBits starts at 0, causing a divide-by-zero via ActiveBits % NarrowBits.

Guard the loop with NarrowBits != 0 to skip the narrowing optimization in this case.
Fixes a crash introduced by #206592, reported via fuzzer testing.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  2 +-
 llvm/test/CodeGen/X86/usubsat-narrow.ll       | 27 +++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 09e26fe2aa58c..5f0b21205b98e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -4726,7 +4726,7 @@ SDValue DAGCombiner::visitSUBSAT(SDNode *N) {
       KnownBits Known0 = DAG.computeKnownBits(N0);
       unsigned ActiveBits = Known0.countMaxActiveBits();
       for (unsigned NarrowBits = PowerOf2Ceil(ActiveBits);
-           NarrowBits < ScalarBits; NarrowBits *= 2) {
+           NarrowBits != 0 && NarrowBits < ScalarBits; NarrowBits *= 2) {
         unsigned Scale = ScalarBits / NarrowBits;
         unsigned NumElts = VT.getVectorNumElements() * Scale;
         MVT NarrowSVT = MVT::getIntegerVT(NarrowBits);
diff --git a/llvm/test/CodeGen/X86/usubsat-narrow.ll b/llvm/test/CodeGen/X86/usubsat-narrow.ll
index 31fd26cd5effe..5ef367c2f298c 100644
--- a/llvm/test/CodeGen/X86/usubsat-narrow.ll
+++ b/llvm/test/CodeGen/X86/usubsat-narrow.ll
@@ -404,3 +404,30 @@ define <8 x i32> @usubsat_v8i32_both_narrow(<8 x i32> %x, <8 x i32> %y) {
   %z = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %mx, <8 x i32> %my)
   ret <8 x i32> %z
 }
+
+; Regression test: known-zero LHS caused divide-by-zero crash in visitSUBSAT
+; when ActiveBits == 0 and NarrowBits == 0.
+define <4 x i32> @usubsat_known_zero_lhs(<4 x i32> %v3) {
+; SSE2-LABEL: usubsat_known_zero_lhs:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    xorps %xmm0, %xmm0
+; SSE2-NEXT:    retq
+;
+; SSE42-LABEL: usubsat_known_zero_lhs:
+; SSE42:       # %bb.0:
+; SSE42-NEXT:    psubd %xmm0, %xmm0
+; SSE42-NEXT:    retq
+;
+; AVX2-LABEL: usubsat_known_zero_lhs:
+; AVX2:       # %bb.0:
+; AVX2-NEXT:    vpsubd %xmm0, %xmm0, %xmm0
+; AVX2-NEXT:    retq
+;
+; AVX512-LABEL: usubsat_known_zero_lhs:
+; AVX512:       # %bb.0:
+; AVX512-NEXT:    vpsubd %xmm0, %xmm0, %xmm0
+; AVX512-NEXT:    retq
+  %v5 = xor <4 x i32> %v3, %v3
+  %v7 = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %v5, <4 x i32> %v3)
+  ret <4 x i32> %v7
+}



More information about the llvm-commits mailing list