[llvm] 349dc34 - [ConstraintElim] Fix poison check before adding intrinsic facts (#136291)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 30 06:46:14 PDT 2025


Author: Iris Shi
Date: 2025-04-30T21:46:07+08:00
New Revision: 349dc34b461a4df6eca4443f5935366cde4508bd

URL: https://github.com/llvm/llvm-project/commit/349dc34b461a4df6eca4443f5935366cde4508bd
DIFF: https://github.com/llvm/llvm-project/commit/349dc34b461a4df6eca4443f5935366cde4508bd.diff

LOG: [ConstraintElim] Fix poison check before adding intrinsic facts (#136291)

Added: 
    llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll

Modified: 
    llvm/test/Transforms/ConstraintElimination/abs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/ConstraintElimination/abs.ll b/llvm/test/Transforms/ConstraintElimination/abs.ll
index 9fc68b0e72663..b9a0c4963211f 100644
--- a/llvm/test/Transforms/ConstraintElimination/abs.ll
+++ b/llvm/test/Transforms/ConstraintElimination/abs.ll
@@ -1,9 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
 ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
 
-define i1 @abs_int_min_is_not_poison(i32 %arg) {
+define i1 @abs_int_min_is_not_poison(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_int_min_is_not_poison(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -12,9 +12,9 @@ define i1 @abs_int_min_is_not_poison(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @abs_int_min_is_poison(i32 %arg) {
+define i1 @abs_int_min_is_poison(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_int_min_is_poison(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -23,9 +23,22 @@ define i1 @abs_int_min_is_poison(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @abs_plus_one(i32 %arg) {
-; CHECK-LABEL: define i1 @abs_plus_one(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+define i1 @abs_plus_one_min_is_not_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @abs_plus_one_min_is_not_poison(
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
+; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nsw i32 [[ABS]], 1
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
+  %abs_plus_one = add nsw i32 %abs, 1
+  %cmp = icmp sge i32 %abs_plus_one, %arg
+  ret i1 %cmp
+}
+
+define i1 @abs_plus_one_min_is_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @abs_plus_one_min_is_poison(
+; CHECK-SAME: i32 noundef [[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
@@ -36,9 +49,23 @@ define i1 @abs_plus_one(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @arg_minus_one_strict_less(i32 %arg) {
-; CHECK-LABEL: define i1 @arg_minus_one_strict_less(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+define i1 @arg_minus_one_strict_less_min_is_not_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @arg_minus_one_strict_less_min_is_not_poison(
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
+; CHECK-NEXT:    [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
+; CHECK-NEXT:    ret i1 true
+;
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
+  %arg_minus_one = add nsw i32 %arg, -1
+  %cmp = icmp slt i32 %arg_minus_one, %abs
+  ret i1 %cmp
+}
+
+
+define i1 @arg_minus_one_strict_less_min_is_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @arg_minus_one_strict_less_min_is_poison(
+; CHECK-SAME: i32 noundef [[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
@@ -49,9 +76,22 @@ define i1 @arg_minus_one_strict_less(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @arg_minus_one_strict_greater(i32 %arg) {
-; CHECK-LABEL: define i1 @arg_minus_one_strict_greater(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+define i1 @arg_minus_one_strict_greater_min_is_not_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @arg_minus_one_strict_greater_min_is_not_poison(
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
+; CHECK-NEXT:    [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
+; CHECK-NEXT:    ret i1 false
+;
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
+  %arg_minus_one = add nsw i32 %arg, -1
+  %cmp = icmp sgt i32 %arg_minus_one, %abs
+  ret i1 %cmp
+}
+
+define i1 @arg_minus_one_strict_greater_min_is_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @arg_minus_one_strict_greater_min_is_poison(
+; CHECK-SAME: i32 noundef [[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
@@ -62,9 +102,26 @@ define i1 @arg_minus_one_strict_greater(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(i32 %arg) {
-; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_not_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_not_poison(
+; CHECK-SAME: i32 noundef [[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 false)
+; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp_arg_nonnegative = icmp sge i32 %arg, 0
+  call void @llvm.assume(i1 %cmp_arg_nonnegative)
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
+  %abs_plus_one = add nuw i32 %abs, 1
+  %cmp = icmp uge i32 %abs_plus_one, %arg
+  ret i1 %cmp
+}
+
+define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_poison(
+; CHECK-SAME: i32 noundef [[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)
@@ -79,15 +136,15 @@ define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(i32 %arg) {
   ret i1 %cmp
 }
 
-define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(i32 %arg) {
+define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
 ; CHECK-NEXT:    [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[ABS_PLUS_ONE]], [[ARG]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
-  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
   %abs_plus_one = add nuw i32 %abs, 1
   %cmp = icmp uge i32 %abs_plus_one, %arg
   ret i1 %cmp
@@ -114,9 +171,9 @@ define i1 @abs_constant_positive_arg() {
   ret i1 %cmp
 }
 
-define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 %arg) {
+define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
@@ -126,21 +183,33 @@ define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 %a
   ret i1 %cmp
 }
 
-define i1 @abs_is_not_strictly_positive(i32 %arg) {
+define i1 @abs_is_not_strictly_positive(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_is_not_strictly_positive(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
-; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ABS]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
-  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
   %cmp = icmp sgt i32 %abs, 0
   ret i1 %cmp
 }
 
-define i1 @abs_is_nonnegative_int_min_is_poison(i32 %arg) {
+define i1 @abs_is_nonnegative_int_min_is_not_poison(i32 noundef %arg) {
+; CHECK-LABEL: define i1 @abs_is_nonnegative_int_min_is_not_poison(
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
+  %cmp = icmp sge i32 %abs, 0
+  ret i1 %cmp
+}
+
+define i1 @abs_is_nonnegative_int_min_is_poison(i32 noundef %arg) {
 ; CHECK-LABEL: define i1 @abs_is_nonnegative_int_min_is_poison(
-; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
 ; CHECK-NEXT:    [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
 ; CHECK-NEXT:    ret i1 true
 ;

diff  --git a/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll b/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll
new file mode 100644
index 0000000000000..42bbe67024e58
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll
@@ -0,0 +1,65 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare i64 @llvm.uadd.sat.i64(i64, i64)
+declare i64 @llvm.usub.sat.i64(i64, i64)
+
+define i1 @uadd_sat_uge(i64 noundef %a, i64 noundef %b) {
+; CHECK-LABEL: define i1 @uadd_sat_uge(
+; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
+; CHECK-NEXT:    [[ADD_SAT:%.*]] = call i64 @llvm.uadd.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i64 [[ADD_SAT]], [[A]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i64 [[ADD_SAT]], [[B]]
+; CHECK-NEXT:    [[CMP:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add.sat = call i64 @llvm.uadd.sat.i64(i64 %a, i64 %b)
+  %cmp1 = icmp uge i64 %add.sat, %a
+  %cmp2 = icmp uge i64 %add.sat, %b
+  %cmp = and i1 %cmp1, %cmp2
+  ret i1 %cmp
+}
+
+define i1 @usub_sat_ule_lhs(i64 noundef %a, i64 noundef %b) {
+; CHECK-LABEL: define i1 @usub_sat_ule_lhs(
+; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
+; CHECK-NEXT:    [[SUB_SAT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i64 [[SUB_SAT]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub.sat = call i64 @llvm.usub.sat.i64(i64 %a, i64 %b)
+  %cmp = icmp ule i64 %sub.sat, %a
+  ret i1 %cmp
+}
+
+; Negative test
+define i1 @usub_sat_not_ule_rhs(i64 noundef %a, i64 noundef %b) {
+; CHECK-LABEL: define i1 @usub_sat_not_ule_rhs(
+; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
+; CHECK-NEXT:    [[SUB_SAT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i64 [[SUB_SAT]], [[B]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub.sat = call i64 @llvm.usub.sat.i64(i64 %a, i64 %b)
+  %cmp = icmp ule i64 %sub.sat, %b
+  ret i1 %cmp
+}
+
+define i1 @pr135603(i64 %conv6, i64 %str.coerce, ptr %conv) {
+; CHECK-LABEL: define i1 @pr135603(
+; CHECK-SAME: i64 [[CONV6:%.*]], i64 [[STR_COERCE:%.*]], ptr [[CONV:%.*]]) {
+; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[CONV]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], -1
+; CHECK-NEXT:    [[CONV2:%.*]] = zext nneg i32 [[A]] to i64
+; CHECK-NEXT:    [[ADD:%.*]] = add i64 [[STR_COERCE]], [[CONV6]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[CONV2]], i64 [[ADD]])
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a = load i32, ptr %conv, align 4
+  %cmp = icmp sgt i32 %a, -1
+  %conv2 = zext nneg i32 %a to i64
+  %add = add i64 %str.coerce, %conv6
+  %spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
+  ret i1 %cmp
+}
+


        


More information about the llvm-commits mailing list