[llvm] [RISCV] Fix infinite DAGCombine loop with SETCC and SIGN_EXTEND_INREG (PR #221593)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 7 11:29:01 PDT 2026


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/221593

>From a9fc9c6431c4e0e41571ecbea8f64c31ab6305cf Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 6 Sep 2026 13:40:32 -0400
Subject: [PATCH 1/4] [RISCV] Fix infinite DAGCombine loop with SETCC and
 SIGN_EXTEND_INREG

We generalized (X & -(1 << C1) & 0xffffffff) == C2 << C1
using `sraiw`. The combine generates a `SIGN_EXTEND_INREG` when simplifying.

However, when C1 is 0 and the sign bit (bit 31) of X is already known to be zero, `DAGCombiner` sees that `SIGN_EXTEND_INREG` is semantically equivalent to `AND X, 0xFFFFFFFF` (zext). Because `DAGCombiner` considers `AND` to be more canonical than `SIGN_EXTEND_INREG` in this context, it immediately reverts the node back to `AND`.

This caused an infinite DAGCombine loop. This patch prevents folding back in this state.

Fixes: https://github.com/llvm/llvm-project/issues/221521
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp    |  8 ++++++++
 .../RISCV/dagcombine-setcc-sext-and-loop.ll    | 18 ++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b2f684952dd90..fa601a8b88d6c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20046,6 +20046,14 @@ static SDValue performSETCCCombine(SDNode *N,
       unsigned ShiftBits = llvm::countr_zero(AndRHSInt);
       int64_t NewC = SignExtend64<32>(N1Int) >> ShiftBits;
       if (NewC >= -2048 && NewC <= 2048) {
+        // If ShiftBits is 0 and the sign bit of X is known zero, DAGCombiner
+        // will fold SIGN_EXTEND_INREG back to AND, causing an infinite loop.
+        if (ShiftBits == 0 &&
+            DAG.MaskedValueIsZero(
+                N0.getOperand(0),
+                APInt::getOneBitSet(OpVT.getScalarSizeInBits(), 31)))
+          return SDValue();
+
         SDValue SExt =
             DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, OpVT, N0.getOperand(0),
                         DAG.getValueType(MVT::i32));
diff --git a/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll b/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll
new file mode 100644
index 0000000000000..6bb7e9d5fec03
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 < %s | FileCheck %s
+
+; This test ensures that the DAGCombiner doesn't get stuck in an infinite loop
+; between RISCVISelLowering converting (X & 0xFFFFFFFF) == C to sext_inreg
+; and DAGCombiner converting sext_inreg back to AND.
+
+define i64 @reproduce(i1 %0) {
+; CHECK-LABEL: reproduce:
+; CHECK:       # %bb.0:
+; CHECK:         ret
+  %2 = select i1 %0, i64 44587060572238, i64 0
+  %3 = and i64 %2, 1005072462
+  %4 = icmp eq i64 %3, 0
+  %5 = zext i1 %4 to i64
+  %6 = or i64 %2, %5
+  ret i64 %6
+}

>From 3f737704fb3953eba12efa16f506724b30a6cc5f Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 6 Sep 2026 20:56:06 -0400
Subject: [PATCH 2/4] getSignMask

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index fa601a8b88d6c..577e30891d144 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20049,9 +20049,8 @@ static SDValue performSETCCCombine(SDNode *N,
         // If ShiftBits is 0 and the sign bit of X is known zero, DAGCombiner
         // will fold SIGN_EXTEND_INREG back to AND, causing an infinite loop.
         if (ShiftBits == 0 &&
-            DAG.MaskedValueIsZero(
-                N0.getOperand(0),
-                APInt::getOneBitSet(OpVT.getScalarSizeInBits(), 31)))
+            DAG.MaskedValueIsZero(N0.getOperand(0),
+                                  APInt::getOneBitSet(64, 31)))
           return SDValue();
 
         SDValue SExt =

>From 9f7fe20fe2493797dbd83cb9f97f6149a2e5808c Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Mon, 7 Sep 2026 14:26:02 -0400
Subject: [PATCH 3/4] Address review comments

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp    |  9 +--------
 llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll     | 16 ++++++++++++++++
 .../RISCV/dagcombine-setcc-sext-and-loop.ll    | 18 ------------------
 3 files changed, 17 insertions(+), 26 deletions(-)
 delete mode 100644 llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 577e30891d144..c25025cafd09c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20045,14 +20045,7 @@ static SDValue performSETCCCombine(SDNode *N,
         isPowerOf2_32(-uint32_t(AndRHSInt)) && (N1Int & AndRHSInt) == N1Int) {
       unsigned ShiftBits = llvm::countr_zero(AndRHSInt);
       int64_t NewC = SignExtend64<32>(N1Int) >> ShiftBits;
-      if (NewC >= -2048 && NewC <= 2048) {
-        // If ShiftBits is 0 and the sign bit of X is known zero, DAGCombiner
-        // will fold SIGN_EXTEND_INREG back to AND, causing an infinite loop.
-        if (ShiftBits == 0 &&
-            DAG.MaskedValueIsZero(N0.getOperand(0),
-                                  APInt::getOneBitSet(64, 31)))
-          return SDValue();
-
+      if (ShiftBits != 0 && NewC >= -2048 && NewC <= 2048) {
         SDValue SExt =
             DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, OpVT, N0.getOperand(0),
                         DAG.getValueType(MVT::i32));
diff --git a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
index 5bd1edb783fce..732ffe272e364 100644
--- a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
+++ b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
@@ -261,3 +261,19 @@ entry:
   %4 = zext i1 %3 to i64
   ret i64 %4
 }
+
+; RV32-LABEL: test14:
+; RV32:       # %bb.0:
+; RV32:         ret
+;
+; RV64-LABEL: test14:
+; RV64:       # %bb.0:
+; RV64:         ret
+define i64 @test14(i1 %0) {
+  %2 = select i1 %0, i64 44587060572238, i64 0
+  %3 = and i64 %2, 1005072462
+  %4 = icmp eq i64 %3, 0
+  %5 = zext i1 %4 to i64
+  %6 = or i64 %2, %5
+  ret i64 %6
+}
diff --git a/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll b/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll
deleted file mode 100644
index 6bb7e9d5fec03..0000000000000
--- a/llvm/test/CodeGen/RISCV/dagcombine-setcc-sext-and-loop.ll
+++ /dev/null
@@ -1,18 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv64 < %s | FileCheck %s
-
-; This test ensures that the DAGCombiner doesn't get stuck in an infinite loop
-; between RISCVISelLowering converting (X & 0xFFFFFFFF) == C to sext_inreg
-; and DAGCombiner converting sext_inreg back to AND.
-
-define i64 @reproduce(i1 %0) {
-; CHECK-LABEL: reproduce:
-; CHECK:       # %bb.0:
-; CHECK:         ret
-  %2 = select i1 %0, i64 44587060572238, i64 0
-  %3 = and i64 %2, 1005072462
-  %4 = icmp eq i64 %3, 0
-  %5 = zext i1 %4 to i64
-  %6 = or i64 %2, %5
-  ret i64 %6
-}

>From 5f2e8d045dbde6820f286281b8aeadf2c6e9be4a Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Mon, 7 Sep 2026 14:28:47 -0400
Subject: [PATCH 4/4] rename

---
 llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll | 28 ++++++++++++++++++----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
index 732ffe272e364..50324a100c4c1 100644
--- a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
+++ b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
@@ -262,14 +262,32 @@ entry:
   ret i64 %4
 }
 
-; RV32-LABEL: test14:
+define i64 @PR221593(i1 %0) {
+; RV32-LABEL: PR221593:
 ; RV32:       # %bb.0:
-; RV32:         ret
+; RV32-NEXT:    lui a1, 245379
+; RV32-NEXT:    slli a0, a0, 31
+; RV32-NEXT:    srai a0, a0, 31
+; RV32-NEXT:    addi a1, a1, 78
+; RV32-NEXT:    lui a2, 3
+; RV32-NEXT:    and a3, a0, a1
+; RV32-NEXT:    addi a1, a2, -1907
+; RV32-NEXT:    seqz a2, a3
+; RV32-NEXT:    and a1, a0, a1
+; RV32-NEXT:    or a0, a3, a2
+; RV32-NEXT:    ret
 ;
-; RV64-LABEL: test14:
+; RV64-LABEL: PR221593:
 ; RV64:       # %bb.0:
-; RV64:         ret
-define i64 @test14(i1 %0) {
+; RV64-NEXT:    lui a1, %hi(.LCPI13_0)
+; RV64-NEXT:    ld a1, %lo(.LCPI13_0)(a1)
+; RV64-NEXT:    slli a0, a0, 63
+; RV64-NEXT:    srai a0, a0, 63
+; RV64-NEXT:    and a0, a0, a1
+; RV64-NEXT:    slli a1, a0, 32
+; RV64-NEXT:    seqz a1, a1
+; RV64-NEXT:    or a0, a0, a1
+; RV64-NEXT:    ret
   %2 = select i1 %0, i64 44587060572238, i64 0
   %3 = and i64 %2, 1005072462
   %4 = icmp eq i64 %3, 0



More information about the llvm-commits mailing list