[llvm] [InstCombine] Fold abs(X, false) --> abs(X, true) If X != INT_MIN (PR #219527)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 28 10:19:30 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Tadeusz (tadeuszjt)

<details>
<summary>Changes</summary>

The second argument of the `llvm.abs` intrinsic determines the behaviour when `X == INT_MIN`. If false, `llvm.abs` will return `INT_MIN`. If true, the return would be a poison. Therefore, the flag can be changed to true if it is known that `X != INT_MIN`.

Alive2 proof: https://alive2.llvm.org/ce/z/NorBAu

Closes: #<!-- -->219528

---
Full diff: https://github.com/llvm/llvm-project/pull/219527.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+13) 
- (modified) llvm/test/Transforms/InstCombine/abs-intrinsic.ll (+25) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 1402c12f2025f..e8a3b9157116c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2216,6 +2216,19 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                               {XY, II->getArgOperand(1)});
     }
 
+    // abs(x, false) -> abs(x, true) if x != INT_MIN
+    if (!IntMinIsPoison) {
+      if (auto *IntTy = dyn_cast<IntegerType>(IIOperand->getType())) {
+        unsigned BitWidth = IntTy->getBitWidth();
+        Constant *IntMin =
+            ConstantInt::get(IntTy, APInt::getSignedMinValue(BitWidth));
+
+        if (isKnownNonEqual(IIOperand, IntMin, SQ.getWithInstruction(II)))
+          return CallInst::Create(II->getCalledFunction(),
+                                  {IIOperand, Builder.getTrue()});
+      }
+    }
+
     if (std::optional<bool> Known =
             getKnownSignOrZero(IIOperand, SQ.getWithInstruction(II))) {
       // abs(x) -> x if x >= 0 (include abs(x-y) --> x - y where x >= y)
diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index f93d0b366ef11..a76f4f0e67406 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -1199,3 +1199,28 @@ define i1 @abs_cmp_ugt_poison_multiuse(i32 %x) {
   %cmp = icmp ugt i32 %x.abs, 31
   ret i1 %cmp
 }
+
+define i8 @abs_no_poison_ne_int_min(i8 %x) {
+; CHECK-LABEL: @abs_no_poison_ne_int_min(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[X:%.*]], -128
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
+; CHECK-NEXT:    ret i8 [[ABS]]
+;
+  %cmp = icmp ne i8 %x, -128
+  call void @llvm.assume(i1 %cmp)
+  %abs = call i8 @llvm.abs.i8(i8 %x, i1 false)
+  ret i8 %abs
+}
+
+define i1 @abs_no_poison_ne_int_min_eq_fold(i32 %x) {
+; CHECK-LABEL: @abs_no_poison_ne_int_min_eq_fold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x1 = or i32 %x, 1
+  %abs = call i32 @llvm.abs.i32(i32 %x1, i1 false)
+  %cmp = icmp eq i32 %abs, %x1
+  ret i1 %cmp
+}
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/219527


More information about the llvm-commits mailing list