[llvm] [DAGCombiner] Fix the "subtraction if above a constant threshold" transform (PR #140042)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Thu May 15 04:14:35 PDT 2025


https://github.com/pfusik created https://github.com/llvm/llvm-project/pull/140042

This fixes #135194 incorrectly leaving `add nuw/nsw` while an unsigned wrap is expected.

>From 3748ec128a4b0a33d405c38c8a4b6dc64d013803 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Thu, 15 May 2025 13:12:42 +0200
Subject: [PATCH] [DAGCombiner] Fix the "subtraction if above a constant
 threshold" transform

This fixes #135194 incorrectly leaving `add nuw/nsw` while an unsigned wrap is expected.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 12 ++++---
 llvm/test/CodeGen/RISCV/rv32zbb.ll            | 31 ++++++++++++++++---
 llvm/test/CodeGen/RISCV/rv64zbb.ll            | 12 +++----
 3 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index d6e288a59b2ee..fc7295c0bc1db 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -12136,15 +12136,19 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
     if (SDValue NewSel = SimplifySelect(DL, N0, N1, N2))
       return NewSel;
 
-    // (select (ugt x, C), (add x, ~C), x) -> (umin (add x, ~C), x)
+    // (select (ugt x, C), (add x, ~C), x) -> (umin x, (add x, ~C))
     // (select (ult x, C), x, (add x, -C)) -> (umin x, (add x, -C))
     APInt C;
     if (sd_match(Cond1, m_ConstInt(C)) && hasUMin(VT)) {
+      APInt AddC;
       if ((CC == ISD::SETUGT && Cond0 == N2 &&
-           sd_match(N1, m_Add(m_Specific(N2), m_SpecificInt(~C)))) ||
+           sd_match(N1, m_Add(m_Specific(N2), m_ConstInt(AddC))) &&
+           AddC == ~C) ||
           (CC == ISD::SETULT && Cond0 == N1 &&
-           sd_match(N2, m_Add(m_Specific(N1), m_SpecificInt(-C)))))
-        return DAG.getNode(ISD::UMIN, DL, VT, N1, N2);
+           sd_match(N2, m_Add(m_Specific(N1), m_ConstInt(AddC))) && AddC == -C))
+        return DAG.getNode(ISD::UMIN, DL, VT, Cond0,
+                           DAG.getNode(ISD::ADD, DL, VT, Cond0,
+                                       DAG.getConstant(AddC, DL, VT)));
     }
   }
 
diff --git a/llvm/test/CodeGen/RISCV/rv32zbb.ll b/llvm/test/CodeGen/RISCV/rv32zbb.ll
index 0f2284637ca6a..0a3729b3de6b6 100644
--- a/llvm/test/CodeGen/RISCV/rv32zbb.ll
+++ b/llvm/test/CodeGen/RISCV/rv32zbb.ll
@@ -1742,7 +1742,7 @@ define i8 @sub_if_uge_C_i8(i8 zeroext %x) {
 ; RV32ZBB:       # %bb.0:
 ; RV32ZBB-NEXT:    addi a1, a0, -13
 ; RV32ZBB-NEXT:    zext.b a1, a1
-; RV32ZBB-NEXT:    minu a0, a1, a0
+; RV32ZBB-NEXT:    minu a0, a0, a1
 ; RV32ZBB-NEXT:    ret
   %cmp = icmp ugt i8 %x, 12
   %sub = add i8 %x, -13
@@ -1763,7 +1763,7 @@ define i16 @sub_if_uge_C_i16(i16 zeroext %x) {
 ; RV32ZBB:       # %bb.0:
 ; RV32ZBB-NEXT:    addi a1, a0, -251
 ; RV32ZBB-NEXT:    zext.h a1, a1
-; RV32ZBB-NEXT:    minu a0, a1, a0
+; RV32ZBB-NEXT:    minu a0, a0, a1
 ; RV32ZBB-NEXT:    ret
   %cmp = icmp ugt i16 %x, 250
   %sub = add i16 %x, -251
@@ -1789,7 +1789,7 @@ define i32 @sub_if_uge_C_i32(i32 signext %x) {
 ; RV32ZBB-NEXT:    lui a1, 1048560
 ; RV32ZBB-NEXT:    addi a1, a1, 15
 ; RV32ZBB-NEXT:    add a1, a0, a1
-; RV32ZBB-NEXT:    minu a0, a1, a0
+; RV32ZBB-NEXT:    minu a0, a0, a1
 ; RV32ZBB-NEXT:    ret
   %cmp = icmp ugt i32 %x, 65520
   %sub = add i32 %x, -65521
@@ -1850,7 +1850,7 @@ define i32 @sub_if_uge_C_multiuse_cmp_i32(i32 signext %x, ptr %z) {
 ; RV32ZBB-NEXT:    addi a3, a3, 15
 ; RV32ZBB-NEXT:    sltu a2, a2, a0
 ; RV32ZBB-NEXT:    add a3, a0, a3
-; RV32ZBB-NEXT:    minu a0, a3, a0
+; RV32ZBB-NEXT:    minu a0, a0, a3
 ; RV32ZBB-NEXT:    sw a2, 0(a1)
 ; RV32ZBB-NEXT:    ret
   %cmp = icmp ugt i32 %x, 65520
@@ -1882,7 +1882,7 @@ define i32 @sub_if_uge_C_multiuse_sub_i32(i32 signext %x, ptr %z) {
 ; RV32ZBB-NEXT:    lui a2, 1048560
 ; RV32ZBB-NEXT:    addi a2, a2, 15
 ; RV32ZBB-NEXT:    add a2, a0, a2
-; RV32ZBB-NEXT:    minu a0, a2, a0
+; RV32ZBB-NEXT:    minu a0, a0, a2
 ; RV32ZBB-NEXT:    sw a2, 0(a1)
 ; RV32ZBB-NEXT:    ret
   %sub = add i32 %x, -65521
@@ -1917,3 +1917,24 @@ define i32 @sub_if_uge_C_swapped_i32(i32 %x) {
   %cond = select i1 %cmp, i32 %x, i32 %sub
   ret i32 %cond
 }
+
+define noundef i8 @sub_if_uge_C_nsw_i8(i8 zeroext %x) {
+; RV32I-LABEL: sub_if_uge_C_nsw_i8:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    sltiu a1, a0, 13
+; RV32I-NEXT:    addi a1, a1, -1
+; RV32I-NEXT:    andi a1, a1, -13
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    ret
+;
+; RV32ZBB-LABEL: sub_if_uge_C_nsw_i8:
+; RV32ZBB:       # %bb.0:
+; RV32ZBB-NEXT:    addi a1, a0, -13
+; RV32ZBB-NEXT:    zext.b a1, a1
+; RV32ZBB-NEXT:    minu a0, a0, a1
+; RV32ZBB-NEXT:    ret
+  %cmp = icmp ugt i8 %x, 12
+  %sub = add nsw i8 %x, -13
+  %conv4 = select i1 %cmp, i8 %sub, i8 %x
+  ret i8 %conv4
+}
diff --git a/llvm/test/CodeGen/RISCV/rv64zbb.ll b/llvm/test/CodeGen/RISCV/rv64zbb.ll
index 17eb0817d548a..1faafbe8b8187 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbb.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbb.ll
@@ -1898,7 +1898,7 @@ define i8 @sub_if_uge_C_i8(i8 zeroext %x) {
 ; RV64ZBB:       # %bb.0:
 ; RV64ZBB-NEXT:    addi a1, a0, -13
 ; RV64ZBB-NEXT:    zext.b a1, a1
-; RV64ZBB-NEXT:    minu a0, a1, a0
+; RV64ZBB-NEXT:    minu a0, a0, a1
 ; RV64ZBB-NEXT:    ret
   %cmp = icmp ugt i8 %x, 12
   %sub = add i8 %x, -13
@@ -1919,7 +1919,7 @@ define i16 @sub_if_uge_C_i16(i16 zeroext %x) {
 ; RV64ZBB:       # %bb.0:
 ; RV64ZBB-NEXT:    addi a1, a0, -251
 ; RV64ZBB-NEXT:    zext.h a1, a1
-; RV64ZBB-NEXT:    minu a0, a1, a0
+; RV64ZBB-NEXT:    minu a0, a0, a1
 ; RV64ZBB-NEXT:    ret
   %cmp = icmp ugt i16 %x, 250
   %sub = add i16 %x, -251
@@ -1945,7 +1945,7 @@ define i32 @sub_if_uge_C_i32(i32 signext %x) {
 ; RV64ZBB-NEXT:    lui a1, 1048560
 ; RV64ZBB-NEXT:    addi a1, a1, 15
 ; RV64ZBB-NEXT:    addw a1, a0, a1
-; RV64ZBB-NEXT:    minu a0, a1, a0
+; RV64ZBB-NEXT:    minu a0, a0, a1
 ; RV64ZBB-NEXT:    ret
   %cmp = icmp ugt i32 %x, 65520
   %sub = add i32 %x, -65521
@@ -1975,7 +1975,7 @@ define i64 @sub_if_uge_C_i64(i64 %x) {
 ; RV64ZBB-NEXT:    addiw a1, a1, -761
 ; RV64ZBB-NEXT:    slli a1, a1, 9
 ; RV64ZBB-NEXT:    add a1, a0, a1
-; RV64ZBB-NEXT:    minu a0, a1, a0
+; RV64ZBB-NEXT:    minu a0, a0, a1
 ; RV64ZBB-NEXT:    ret
   %cmp = icmp ugt i64 %x, 4999999999
   %sub = add i64 %x, -5000000000
@@ -2005,7 +2005,7 @@ define i32 @sub_if_uge_C_multiuse_cmp_i32(i32 signext %x, ptr %z) {
 ; RV64ZBB-NEXT:    addi a3, a3, 15
 ; RV64ZBB-NEXT:    sltu a2, a2, a0
 ; RV64ZBB-NEXT:    addw a3, a0, a3
-; RV64ZBB-NEXT:    minu a0, a3, a0
+; RV64ZBB-NEXT:    minu a0, a0, a3
 ; RV64ZBB-NEXT:    sw a2, 0(a1)
 ; RV64ZBB-NEXT:    ret
   %cmp = icmp ugt i32 %x, 65520
@@ -2037,7 +2037,7 @@ define i32 @sub_if_uge_C_multiuse_sub_i32(i32 signext %x, ptr %z) {
 ; RV64ZBB-NEXT:    lui a2, 1048560
 ; RV64ZBB-NEXT:    addi a2, a2, 15
 ; RV64ZBB-NEXT:    addw a2, a0, a2
-; RV64ZBB-NEXT:    minu a0, a2, a0
+; RV64ZBB-NEXT:    minu a0, a0, a2
 ; RV64ZBB-NEXT:    sw a2, 0(a1)
 ; RV64ZBB-NEXT:    ret
   %sub = add i32 %x, -65521



More information about the llvm-commits mailing list