[llvm] 88d26e7 - [ConstraintElim] Add tests with SRem and NE predicates. (NFC (#212511)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 28 08:23:52 PDT 2026
Author: Florian Hahn
Date: 2026-07-28T15:23:45Z
New Revision: 88d26e71960579c5a7b40856664b1f57791597ce
URL: https://github.com/llvm/llvm-project/commit/88d26e71960579c5a7b40856664b1f57791597ce
DIFF: https://github.com/llvm/llvm-project/commit/88d26e71960579c5a7b40856664b1f57791597ce.diff
LOG: [ConstraintElim] Add tests with SRem and NE predicates. (NFC (#212511)
Precommit tests for improved reasoning about SRem and NE predicates.
Added:
llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
llvm/test/Transforms/ConstraintElimination/srem.ll
Modified:
Removed:
################################################################################
diff --git a/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll b/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
new file mode 100644
index 0000000000000..a7967e9b09051
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
@@ -0,0 +1,310 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @llvm.assume(i1)
+
+define i1 @sge_zero_and_ne_zero_implies_sgt_zero(i64 %n) {
+; CHECK-LABEL: define i1 @sge_zero_and_ne_zero_implies_sgt_zero(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp sgt i64 %n, 0
+ ret i1 %c
+}
+
+define i1 @sge_zero_and_ne_zero_from_branch(i64 %n) {
+; CHECK-LABEL: define i1 @sge_zero_and_ne_zero_from_branch(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[Z:%.*]] = icmp eq i64 [[N]], 0
+; CHECK-NEXT: br i1 [[Z]], label %[[ELSE:.*]], label %[[CONT:.*]]
+; CHECK: [[CONT]]:
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %z = icmp eq i64 %n, 0
+ br i1 %z, label %else, label %cont
+
+cont:
+ %c = icmp sgt i64 %n, 0
+ ret i1 %c
+
+else:
+ ret i1 false
+}
+
+define i1 @sle_zero_and_ne_zero_implies_slt_zero(i64 %n) {
+; CHECK-LABEL: define i1 @sle_zero_and_ne_zero_implies_slt_zero(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sle i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sle i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp slt i64 %n, 0
+ ret i1 %c
+}
+
+define i1 @sge_const_and_ne_const_implies_sge_const_plus_one(i64 %n) {
+; CHECK-LABEL: define i1 @sge_const_and_ne_const_implies_sge_const_plus_one(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sge i64 [[N]], 11
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 10
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 10
+ call void @llvm.assume(i1 %b)
+ %c = icmp sge i64 %n, 11
+ ret i1 %c
+}
+
+define i1 @sle_const_and_ne_const_implies_sle_const_minus_one(i64 %n) {
+; CHECK-LABEL: define i1 @sle_const_and_ne_const_implies_sle_const_minus_one(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sle i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sle i64 [[N]], 9
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sle i64 %n, 10
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 10
+ call void @llvm.assume(i1 %b)
+ %c = icmp sle i64 %n, 9
+ ret i1 %c
+}
+
+define i1 @uge_const_and_ne_const_implies_ugt_const(i64 %n) {
+; CHECK-LABEL: define i1 @uge_const_and_ne_const_implies_ugt_const(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp uge i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp ugt i64 [[N]], 10
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp uge i64 %n, 10
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 10
+ call void @llvm.assume(i1 %b)
+ %c = icmp ugt i64 %n, 10
+ ret i1 %c
+}
+
+; n u<= 10 /\ n != 10 ==> n u< 10.
+define i1 @ule_const_and_ne_const_implies_ult_const(i64 %n) {
+; CHECK-LABEL: define i1 @ule_const_and_ne_const_implies_ult_const(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp ule i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[N]], 10
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp ule i64 %n, 10
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 10
+ call void @llvm.assume(i1 %b)
+ %c = icmp ult i64 %n, 10
+ ret i1 %c
+}
+
+define i1 @sge_and_ne_on_add(i64 %n) {
+; CHECK-LABEL: define i1 @sge_and_ne_on_add(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[N]], 1
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[ADD]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[ADD]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %add = add nsw i64 %n, 1
+ %a = icmp sge i64 %add, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %add, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp sge i64 %n, 0
+ ret i1 %c
+}
+
+define i1 @ne_zero_implies_ugt_zero(i64 %n) {
+; CHECK-LABEL: define i1 @ne_zero_implies_ugt_zero(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: ret i1 true
+;
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp ugt i64 %n, 0
+ ret i1 %c
+}
+
+; Without a known sign for n, n != 0 says nothing about n >= 1 in the signed
+; system.
+define i1 @neg_ne_zero_without_sign(i64 %n) {
+; CHECK-LABEL: define i1 @neg_ne_zero_without_sign(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp sgt i64 %n, 0
+ ret i1 %c
+}
+
+define i1 @neg_ne_other_const_does_not_tighten_bound(i64 %n) {
+; CHECK-LABEL: define i1 @neg_ne_other_const_does_not_tighten_bound(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 5
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 5
+ call void @llvm.assume(i1 %b)
+ %c = icmp sgt i64 %n, 0
+ ret i1 %c
+}
+
+define i1 @neg_ne_const_above_bound(i64 %n) {
+; CHECK-LABEL: define i1 @neg_ne_const_above_bound(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 5
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sge i64 [[N]], 6
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 5
+ call void @llvm.assume(i1 %b)
+ %c = icmp sge i64 %n, 6
+ ret i1 %c
+}
+
+define i1 @neg_tightening_is_by_one_only(i64 %n) {
+; CHECK-LABEL: define i1 @neg_tightening_is_by_one_only(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sge i64 [[N]], 2
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %c = icmp sge i64 %n, 2
+ ret i1 %c
+}
+
+define i1 @neg_ne_non_constant(i64 %n, i64 %m) {
+; CHECK-LABEL: define i1 @neg_ne_non_constant(
+; CHECK-SAME: i64 [[N:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, %m
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, %m
+ call void @llvm.assume(i1 %b)
+ %c = icmp sgt i64 %n, %m
+ ret i1 %c
+}
+
+define i1 @neg_no_tightening_at_smax(i64 %n) {
+; CHECK-LABEL: define i1 @neg_no_tightening_at_smax(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 9223372036854775807
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[N]], 9223372036854775807
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %b = icmp ne i64 %n, 9223372036854775807
+ call void @llvm.assume(i1 %b)
+ %c = icmp slt i64 %n, 9223372036854775807
+ ret i1 %c
+}
+
+define i1 @neg_no_tightening_at_smin(i64 %n) {
+; CHECK-LABEL: define i1 @neg_no_tightening_at_smin(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], -9223372036854775808
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[N]], -9223372036854775808
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %b = icmp ne i64 %n, -9223372036854775808
+ call void @llvm.assume(i1 %b)
+ %c = icmp sgt i64 %n, -9223372036854775808
+ ret i1 %c
+}
+
+define i1 @tightened_bound_enables_srem_fact(i64 noundef %x, i64 noundef %n) {
+; CHECK-LABEL: define i1 @tightened_bound_enables_srem_fact(
+; CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[N:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = icmp sge i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[B]])
+; CHECK-NEXT: [[R:%.*]] = srem i64 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[R]], [[N]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = icmp sge i64 %n, 0
+ call void @llvm.assume(i1 %a)
+ %b = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %b)
+ %r = srem i64 %x, %n
+ %c = icmp slt i64 %r, %n
+ ret i1 %c
+}
diff --git a/llvm/test/Transforms/ConstraintElimination/srem.ll b/llvm/test/Transforms/ConstraintElimination/srem.ll
new file mode 100644
index 0000000000000..3a53a8ffba1f8
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/srem.ll
@@ -0,0 +1,298 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @llvm.assume(i1)
+
+define i1 @srem_sge_zero(i32 noundef %x, i32 noundef %n) {
+; CHECK-LABEL: define i1 @srem_sge_zero(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sge i32 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %cmp = icmp sge i32 %x, 0
+ call void @llvm.assume(i1 %cmp)
+ %r = srem i32 %x, %n
+ %c = icmp sge i32 %r, 0
+ ret i1 %c
+}
+
+define i1 @srem_slt_divisor_bound(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @srem_slt_divisor_bound(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[POS:%.*]] = icmp sgt i32 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POS]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %pos = icmp sgt i32 %n, 0
+ call void @llvm.assume(i1 %pos)
+ %le = icmp sle i32 %n, %m
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp slt i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @srem_sle_dividend_bound(i32 noundef %x, i32 noundef %n, i32 noundef %limit) {
+; CHECK-LABEL: define i1 @srem_sle_dividend_bound(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[LIMIT:%.*]]) {
+; CHECK-NEXT: [[NNEG:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NNEG]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[X]], [[LIMIT]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sle i32 [[R]], [[LIMIT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nneg = icmp sge i32 %x, 0
+ call void @llvm.assume(i1 %nneg)
+ %le = icmp sle i32 %x, %limit
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp sle i32 %r, %limit
+ ret i1 %c
+}
+
+define i1 @srem_ult_divisor_bound_via_transfer(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @srem_ult_divisor_bound_via_transfer(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[NNEG:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NNEG]])
+; CHECK-NEXT: [[POS:%.*]] = icmp sgt i32 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POS]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nneg = icmp sge i32 %x, 0
+ call void @llvm.assume(i1 %nneg)
+ %pos = icmp sgt i32 %n, 0
+ call void @llvm.assume(i1 %pos)
+ %le = icmp sle i32 %n, %m
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp ult i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @srem_const_dividend(i32 noundef %n) {
+; CHECK-LABEL: define i1 @srem_const_dividend(
+; CHECK-SAME: i32 noundef [[N:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = srem i32 42, [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sge i32 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %r = srem i32 42, %n
+ %c = icmp sge i32 %r, 0
+ ret i1 %c
+}
+
+define i1 @srem_const_divisor(i32 noundef %x) {
+; CHECK-LABEL: define i1 @srem_const_divisor(
+; CHECK-SAME: i32 noundef [[X:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 10
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 10
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %r = srem i32 %x, 10
+ %c = icmp slt i32 %r, 10
+ ret i1 %c
+}
+
+define i1 @srem_i64(i64 noundef %x, i64 noundef %n, i64 noundef %m) {
+; CHECK-LABEL: define i1 @srem_i64(
+; CHECK-SAME: i64 noundef [[X:%.*]], i64 noundef [[N:%.*]], i64 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[POS:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POS]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i64 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i64 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %pos = icmp sgt i64 %n, 0
+ call void @llvm.assume(i1 %pos)
+ %le = icmp sle i64 %n, %m
+ call void @llvm.assume(i1 %le)
+ %r = srem i64 %x, %n
+ %c = icmp slt i64 %r, %m
+ ret i1 %c
+}
+
+define i1 @neg_srem_dividend_sign_unknown(i32 noundef %x, i32 noundef %n) {
+; CHECK-LABEL: define i1 @neg_srem_dividend_sign_unknown(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sge i32 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %r = srem i32 %x, %n
+ %c = icmp sge i32 %r, 0
+ ret i1 %c
+}
+
+define i1 @neg_srem_negative_dividend(i32 noundef %x, i32 noundef %n) {
+; CHECK-LABEL: define i1 @neg_srem_negative_dividend(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sge i32 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %cmp = icmp slt i32 %x, 0
+ call void @llvm.assume(i1 %cmp)
+ %r = srem i32 %x, %n
+ %c = icmp sge i32 %r, 0
+ ret i1 %c
+}
+
+define i1 @neg_srem_negative_dividend_upper_bound(i32 noundef %x, i32 noundef %n, i32 noundef %limit) {
+; CHECK-LABEL: define i1 @neg_srem_negative_dividend_upper_bound(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[LIMIT:%.*]]) {
+; CHECK-NEXT: [[NEG:%.*]] = icmp slt i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NEG]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[X]], [[LIMIT]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sle i32 [[R]], [[LIMIT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %neg = icmp slt i32 %x, 0
+ call void @llvm.assume(i1 %neg)
+ %le = icmp sle i32 %x, %limit
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp sle i32 %r, %limit
+ ret i1 %c
+}
+
+define i1 @neg_srem_divisor_may_be_zero(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @neg_srem_divisor_may_be_zero(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[NNEG:%.*]] = icmp sge i32 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NNEG]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nneg = icmp sge i32 %n, 0
+ call void @llvm.assume(i1 %nneg)
+ %le = icmp sle i32 %n, %m
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp slt i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @neg_srem_negative_divisor(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @neg_srem_negative_divisor(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[NEG:%.*]] = icmp slt i32 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NEG]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %neg = icmp slt i32 %n, 0
+ call void @llvm.assume(i1 %neg)
+ %le = icmp sle i32 %n, %m
+ call void @llvm.assume(i1 %le)
+ %r = srem i32 %x, %n
+ %c = icmp slt i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @neg_srem_unsigned_divisor_bound(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @neg_srem_unsigned_divisor_bound(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[N]], [[M]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %cmp = icmp ult i32 %n, %m
+ call void @llvm.assume(i1 %cmp)
+ %r = srem i32 %x, %n
+ %c = icmp slt i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @neg_srem_no_noundef(i32 %x, i32 %n) {
+; CHECK-LABEL: define i1 @neg_srem_no_noundef(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[MID:.*]], label %[[ELSE:.*]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sge i32 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cmp = icmp sge i32 %x, 0
+ br i1 %cmp, label %mid, label %else
+
+mid:
+ %r = srem i32 %x, %n
+ %c = icmp sge i32 %r, 0
+ ret i1 %c
+
+else:
+ ret i1 false
+}
+
+define i1 @neg_srem_wrong_direction(i32 noundef %x, i32 noundef %n, i32 noundef %m) {
+; CHECK-LABEL: define i1 @neg_srem_wrong_direction(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[M:%.*]]) {
+; CHECK-NEXT: [[POS:%.*]] = icmp sgt i32 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POS]])
+; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[M]], [[N]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LT]])
+; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], [[M]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %pos = icmp sgt i32 %n, 0
+ call void @llvm.assume(i1 %pos)
+ %lt = icmp slt i32 %m, %n
+ call void @llvm.assume(i1 %lt)
+ %r = srem i32 %x, %n
+ %c = icmp slt i32 %r, %m
+ ret i1 %c
+}
+
+define i1 @neg_sdiv_not_handled(i32 noundef %x, i32 noundef %n, i32 noundef %limit) {
+; CHECK-LABEL: define i1 @neg_sdiv_not_handled(
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[N:%.*]], i32 noundef [[LIMIT:%.*]]) {
+; CHECK-NEXT: [[NNEG:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NNEG]])
+; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[X]], [[LIMIT]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[LE]])
+; CHECK-NEXT: [[Q:%.*]] = sdiv i32 [[X]], [[N]]
+; CHECK-NEXT: [[C:%.*]] = icmp sle i32 [[Q]], [[LIMIT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nneg = icmp sge i32 %x, 0
+ call void @llvm.assume(i1 %nneg)
+ %le = icmp sle i32 %x, %limit
+ call void @llvm.assume(i1 %le)
+ %q = sdiv i32 %x, %n
+ %c = icmp sle i32 %q, %limit
+ ret i1 %c
+}
More information about the llvm-commits
mailing list