[llvm-branch-commits] [llvm] [ConstraintElim] Opimize abs based on known constraints (PR #135754)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Apr 15 07:56:24 PDT 2025


https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/135754

>From 370305c4926ec615ff1d0408afad145279a721fe Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 15:00:58 +0800
Subject: [PATCH 1/4] [ConstraintElim] Opimize abs based on known constraints

---
 .../Scalar/ConstraintElimination.cpp          | 29 ++++++++++++-
 .../Transforms/ConstraintElimination/abs.ll   | 43 +++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 6af5d2c1c0b7b..d544b5a19920d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1128,12 +1128,12 @@ void State::addInfoFor(BasicBlock &BB) {
           FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
       break;
     // Enqueue the intrinsics to add extra info.
+    case Intrinsic::abs:
     case Intrinsic::umin:
     case Intrinsic::umax:
     case Intrinsic::smin:
     case Intrinsic::smax:
     case Intrinsic::usub_sat:
-    // TODO: handle llvm.abs as well
       WorkList.push_back(
           FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
       // TODO: Check if it is possible to instead only added the min/max facts
@@ -1141,7 +1141,6 @@ void State::addInfoFor(BasicBlock &BB) {
       if (!isGuaranteedNotToBePoison(&I))
         break;
       [[fallthrough]];
-    case Intrinsic::abs:
     case Intrinsic::uadd_sat:
       WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));
       break;
@@ -1537,6 +1536,28 @@ static bool checkAndReplaceUSubSat(SaturatingInst *I, ConstraintInfo &Info,
   return false;
 }
 
+static bool checkAndReplaceAbs(IntrinsicInst *I, ConstraintInfo &Info,
+                               SmallVectorImpl<Instruction *> &ToRemove) {
+  assert(I->getIntrinsicID() == Intrinsic::abs && "Expected abs intrinsic");
+  Value *Op = I->getOperand(0);
+  if (checkCondition(ICmpInst::ICMP_SGE, Op, ConstantInt::get(Op->getType(), 0),
+                     I, Info)
+          .value_or(false)) {
+    I->replaceAllUsesWith(Op);
+    ToRemove.push_back(I);
+    return true;
+  }
+  if (checkCondition(ICmpInst::ICMP_SLT, Op, ConstantInt::get(Op->getType(), 0),
+                     I, Info)
+          .value_or(false)) {
+    IRBuilder<> Builder(I->getParent(), I->getIterator());
+    I->replaceAllUsesWith(Builder.CreateNeg(Op));
+    ToRemove.push_back(I);
+    return true;
+  }
+  return false;
+}
+
 static void
 removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
                      Module *ReproducerModule,
@@ -1863,6 +1884,10 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
           Changed |= checkAndReplaceUSubSat(SatIntr, Info, ToRemove);
         else
           llvm_unreachable("Unexpected intrinsic.");
+      } else if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
+        if (II->getIntrinsicID() == Intrinsic::abs) {
+          Changed |= checkAndReplaceAbs(II, Info, ToRemove);
+        }
       }
       continue;
     }
diff --git a/llvm/test/Transforms/ConstraintElimination/abs.ll b/llvm/test/Transforms/ConstraintElimination/abs.ll
index 9fc68b0e72663..32f686a6fcb8f 100644
--- a/llvm/test/Transforms/ConstraintElimination/abs.ll
+++ b/llvm/test/Transforms/ConstraintElimination/abs.ll
@@ -159,5 +159,48 @@ define i1 @abs_is_nonnegative_constant_arg() {
   ret i1 %cmp
 }
 
+define i64 @abs_assume_nonnegative(i64 %arg) {
+; CHECK-LABEL: define i64 @abs_assume_nonnegative(
+; CHECK-SAME: i64 [[ARG:%.*]]) {
+; CHECK-NEXT:    [[PRECOND:%.*]] = icmp sge i64 [[ARG]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[ARG]], i1 false)
+; CHECK-NEXT:    ret i64 [[ABS]]
+;
+  %precond = icmp sge i64 %arg, 0
+  call void @llvm.assume(i1 %precond)
+  %abs = tail call i64 @llvm.abs.i64(i64 %arg, i1 false)
+  ret i64 %abs
+}
+
+define i64 @abs_assume_negative(i64 %arg) {
+; CHECK-LABEL: define i64 @abs_assume_negative(
+; CHECK-SAME: i64 [[ARG:%.*]]) {
+; CHECK-NEXT:    [[PRECOND:%.*]] = icmp slt i64 [[ARG]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[ARG]], i1 false)
+; CHECK-NEXT:    ret i64 [[ABS]]
+;
+  %precond = icmp slt i64 %arg, 0
+  call void @llvm.assume(i1 %precond)
+  %abs = tail call i64 @llvm.abs.i64(i64 %arg, i1 false)
+  ret i64 %abs
+}
+
+; Negative test
+define i64 @abs_assume_unrelated(i64 %arg) {
+; CHECK-LABEL: define i64 @abs_assume_unrelated(
+; CHECK-SAME: i64 [[ARG:%.*]]) {
+; CHECK-NEXT:    [[PRECOND:%.*]] = icmp slt i64 [[ARG]], 3
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[ARG]], i1 false)
+; CHECK-NEXT:    ret i64 [[ABS]]
+;
+  %precond = icmp slt i64 %arg, 3
+  call void @llvm.assume(i1 %precond)
+  %abs = tail call i64 @llvm.abs.i64(i64 %arg, i1 false)
+  ret i64 %abs
+}
+
 declare i32 @llvm.abs.i32(i32, i1 immarg)
 declare void @llvm.assume(i1)

>From 2db858edaff1f8f959090a3db9614c67b42d8e04 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 15:03:08 +0800
Subject: [PATCH 2/4] update test

---
 llvm/test/Transforms/ConstraintElimination/abs.ll | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/llvm/test/Transforms/ConstraintElimination/abs.ll b/llvm/test/Transforms/ConstraintElimination/abs.ll
index 32f686a6fcb8f..e09a061410f48 100644
--- a/llvm/test/Transforms/ConstraintElimination/abs.ll
+++ b/llvm/test/Transforms/ConstraintElimination/abs.ll
@@ -67,8 +67,7 @@ define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(i32 %arg) {
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[CMP_ARG_NONNEGATIVE:%.*]] = icmp sge i32 [[ARG]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_ARG_NONNEGATIVE]])
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
-; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
+; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ARG]], 1
 ; CHECK-NEXT:    ret i1 true
 ;
   %cmp_arg_nonnegative = icmp sge i32 %arg, 0
@@ -95,9 +94,7 @@ define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(i32 %arg)
 
 define i1 @abs_constant_negative_arg() {
 ; CHECK-LABEL: define i1 @abs_constant_negative_arg() {
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 -3, i1 false)
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], 3
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 true
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 -3, i1 false)
   %cmp = icmp sge i32 %abs, 3
@@ -106,7 +103,6 @@ define i1 @abs_constant_negative_arg() {
 
 define i1 @abs_constant_positive_arg() {
 ; CHECK-LABEL: define i1 @abs_constant_positive_arg() {
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 3, i1 false)
 ; CHECK-NEXT:    ret i1 true
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 3, i1 false)
@@ -151,7 +147,6 @@ define i1 @abs_is_nonnegative_int_min_is_poison(i32 %arg) {
 
 define i1 @abs_is_nonnegative_constant_arg() {
 ; CHECK-LABEL: define i1 @abs_is_nonnegative_constant_arg() {
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 -3, i1 true)
 ; CHECK-NEXT:    ret i1 true
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 -3, i1 true)
@@ -164,8 +159,7 @@ define i64 @abs_assume_nonnegative(i64 %arg) {
 ; CHECK-SAME: i64 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[PRECOND:%.*]] = icmp sge i64 [[ARG]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[ARG]], i1 false)
-; CHECK-NEXT:    ret i64 [[ABS]]
+; CHECK-NEXT:    ret i64 [[ARG]]
 ;
   %precond = icmp sge i64 %arg, 0
   call void @llvm.assume(i1 %precond)
@@ -178,7 +172,7 @@ define i64 @abs_assume_negative(i64 %arg) {
 ; CHECK-SAME: i64 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[PRECOND:%.*]] = icmp slt i64 [[ARG]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[ARG]], i1 false)
+; CHECK-NEXT:    [[ABS:%.*]] = sub i64 0, [[ARG]]
 ; CHECK-NEXT:    ret i64 [[ABS]]
 ;
   %precond = icmp slt i64 %arg, 0

>From a20c02f3bb6275d6b7dbf1005d46df95734311c5 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 16:58:39 +0800
Subject: [PATCH 3/4] match abs only

---
 llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index d544b5a19920d..b8af323a4fe73 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1879,15 +1879,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
         Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove);
       } else if (auto *CmpIntr = dyn_cast<CmpIntrinsic>(Inst)) {
         Changed |= checkAndReplaceCmp(CmpIntr, Info, ToRemove);
+      } else if (match(Inst, m_Intrinsic<Intrinsic::abs>(m_Value()))) {
+        Changed |=
+            checkAndReplaceAbs(dyn_cast<IntrinsicInst>(Inst), Info, ToRemove);
       } else if (auto *SatIntr = dyn_cast<SaturatingInst>(Inst)) {
         if (SatIntr->getIntrinsicID() == Intrinsic::usub_sat)
           Changed |= checkAndReplaceUSubSat(SatIntr, Info, ToRemove);
         else
           llvm_unreachable("Unexpected intrinsic.");
-      } else if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
-        if (II->getIntrinsicID() == Intrinsic::abs) {
-          Changed |= checkAndReplaceAbs(II, Info, ToRemove);
-        }
       }
       continue;
     }

>From 6e3bb6129cf08c715bd7321560955f0edf52f07c Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 21:29:43 +0800
Subject: [PATCH 4/4] add nopoison back

---
 .../Transforms/ConstraintElimination/abs.ll    | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/llvm/test/Transforms/ConstraintElimination/abs.ll b/llvm/test/Transforms/ConstraintElimination/abs.ll
index e09a061410f48..a49b4643ab92c 100644
--- a/llvm/test/Transforms/ConstraintElimination/abs.ll
+++ b/llvm/test/Transforms/ConstraintElimination/abs.ll
@@ -5,7 +5,8 @@ define i1 @abs_int_min_is_not_poison(i32 %arg) {
 ; CHECK-LABEL: define i1 @abs_int_min_is_not_poison(
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], [[ARG]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
   %cmp = icmp sge i32 %abs, %arg
@@ -16,7 +17,8 @@ define i1 @abs_int_min_is_poison(i32 %arg) {
 ; CHECK-LABEL: define i1 @abs_int_min_is_poison(
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], [[ARG]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %cmp = icmp sge i32 %abs, %arg
@@ -28,7 +30,8 @@ define i1 @abs_plus_one(i32 %arg) {
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
 ; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nsw i32 [[ABS]], 1
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS_PLUS_ONE]], [[ARG]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %abs_plus_one = add nsw i32 %abs, 1
@@ -41,7 +44,8 @@ define i1 @arg_minus_one_strict_less(i32 %arg) {
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
 ; CHECK-NEXT:    [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ARG_MINUS_ONE]], [[ABS]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %arg_minus_one = add nsw i32 %arg, -1
@@ -54,7 +58,8 @@ define i1 @arg_minus_one_strict_greater(i32 %arg) {
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
 ; CHECK-NEXT:    [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
-; CHECK-NEXT:    ret i1 false
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ARG_MINUS_ONE]], [[ABS]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %arg_minus_one = add nsw i32 %arg, -1
@@ -138,7 +143,8 @@ define i1 @abs_is_nonnegative_int_min_is_poison(i32 %arg) {
 ; CHECK-LABEL: define i1 @abs_is_nonnegative_int_min_is_poison(
 ; CHECK-SAME: i32 [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %cmp = icmp sge i32 %abs, 0



More information about the llvm-branch-commits mailing list