[llvm] [llvm][InstCombine] Fold signum(x) into scmp(x, 0) (PR #143445)

Yash Solanki via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 9 14:45:50 PDT 2025


https://github.com/yashnator created https://github.com/llvm/llvm-project/pull/143445

Currently:

```cpp
int signum(int x) {
    if (x < 0) return -1;
    if (x > 0) return +1;
    return 0;
}
```

is not identified as `scmp(x,0)`.

This patch adds folding for the edge case: `(x > -1) ? zext(x != 0) : -1`, which is generated for the above signum and is equivalent to `scmp(x, 0)`. For other constants/variables, the fold is already optimised.

[Alive2 proof](https://alive2.llvm.org/ce/z/EYQZwV) (taken from issue)

Resolves #143259

>From 21d25005fc8e6e3d665ec161a3cdbdece75aa660 Mon Sep 17 00:00:00 2001
From: Yash Solanki <252yash at gmail.com>
Date: Tue, 10 Jun 2025 02:53:42 +0530
Subject: [PATCH] [InstCombine] Fold (x > -1) ? zext(x != 0) : -1 into scmp

Add folding for the edge case:
  (x > -1) ? zext(x != 0) : -1

This pattern is equivalent to signum(x), and can be replaced
with a scmp to enable better canonicalization and optimization.

Resolves #143259
---
 .../Transforms/InstCombine/InstCombineSelect.cpp   | 12 ++++++++++++
 llvm/test/Transforms/InstCombine/scmp.ll           | 14 ++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 8f46ae304353d..ec0cda18a6492 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3603,6 +3603,18 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
        ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred))
     Replace = true;
 
+  // Handle the edge case (x > -1) ? zext(x != 0), -1
+  if (IsSigned && ICmpInst::isGT(Pred) && match(FV, m_AllOnes()) &&
+      match(TV, m_ZExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
+                                m_Zero()))) &&
+      (ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
+       ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred)) {
+    Value *Zero = ConstantInt::get(LHS->getType(), 0);
+    return replaceInstUsesWith(
+        SI,
+        Builder.CreateIntrinsic(SI.getType(), Intrinsic::scmp, {LHS, Zero}));
+  }
+
   // (x == y) ? 0 : (x > y ? 1 : -1)
   CmpPredicate FalseBranchSelectPredicate;
   const APInt *InnerTV, *InnerFV;
diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 2140a59de3fa9..b685ca20998bd 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -473,3 +473,17 @@ define i8 @scmp_from_select_eq_and_gt_neg3(i32 %x, i32 %y) {
   %r = select i1 %eq, i8 0, i8 %sel1
   ret i8 %r
 }
+
+; Fold (x > -1) ? zext(x != 0), -1 to scmp(x, 0)
+define i32 @scmp_x_0_from_gt_minus_1(i32 noundef %0) local_unnamed_addr #0 {
+; CHECK-LABEL: define i32 @scmp_x_0_from_gt_minus_1(
+; CHECK-SAME: i32 noundef [[TMP0:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    [[TMP2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[TMP0]], i32 0)
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+  %2 = icmp ne i32 %0, 0
+  %3 = zext i1 %2 to i32
+  %4 = icmp sgt i32 %0, -1
+  %5 = select i1 %4, i32 %3, i32 -1
+  ret i32 %5
+}



More information about the llvm-commits mailing list