[llvm] [InstCombine] Add fold `(x * z) % (y * z) == 0` -> `x % y == 0` (PR #171655)
Ashish Ahuja via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 10 09:14:57 PST 2025
https://github.com/double-fault created https://github.com/llvm/llvm-project/pull/171655
Alive2: https://alive2.llvm.org/ce/z/ylAxft
Partially implements #76585. Does not implement the case mentioned in the first comment on the issue, i.e when we have constants with common factors - this patch already got a bit long with the tests so I think it'll be better to do that as a separate patch.
Few things to note:
- This folds both `icmp eq` and `icmp ne`, but I have only added trivial tests for `icmp ne` as otherwise each test would get duplicated which I think is unnecessary.
- Does not fold when the comparison constant is a zero vector with some poison values; further up the call chain the constant is matched with `m_APInt` which I think does not match such a vector, and supporting such folds would require a lot more code changes.
Thanks
>From d933fb8c7ef0017bb1eae18fc8308d1a90231695 Mon Sep 17 00:00:00 2001
From: Ashish Ahuja <shivashish.ahuja at gmail.com>
Date: Wed, 10 Dec 2025 20:18:41 +0530
Subject: [PATCH 1/2] [InstCombine][NFC] Add tests for '(xz rem yz) == 0 -> (x
rem y) == 0' fold
---
llvm/test/Transforms/InstCombine/icmp-rem.ll | 561 +++++++++++++++++++
1 file changed, 561 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/icmp-rem.ll
diff --git a/llvm/test/Transforms/InstCombine/icmp-rem.ll b/llvm/test/Transforms/InstCombine/icmp-rem.ll
new file mode 100644
index 0000000000000..93d5aae524467
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-rem.ll
@@ -0,0 +1,561 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @use(i8)
+
+define i1 @icmp_eq_srem_mul(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %z, %x
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %z, %y
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_commuted3(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted3(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %z, %x
+ %b = mul nsw i8 %z, %y
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_multi_use(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: call void @use(i8 [[A]])
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: call void @use(i8 [[B]])
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ call void @use(i8 %a)
+ %b = mul nsw i8 %y, %z
+ call void @use(i8 %b)
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_ne_srem_mul(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_ne_srem_mul(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp ne i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_const1(i8 %x, i8 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], -2
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], -2
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, -2
+ %b = mul nsw i8 %y, -2
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_const2(i8 %x, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], -3
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %z, -3
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_const3(i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const3(
+; CHECK-SAME: i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], -3
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %z, -3
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define <2 x i1> @icmp_eq_srem_mul_vec_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_srem_mul_vec_splat(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nsw <2 x i8> %x, %z
+ %b = mul nsw <2 x i8> %y, %z
+ %r = srem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, zeroinitializer
+ ret <2 x i1> %c
+}
+
+define <2 x i1> @icmp_eq_srem_mul_vec_splat_poison(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_srem_mul_vec_splat_poison(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], <i8 0, i8 poison>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nsw <2 x i8> %x, %z
+ %b = mul nsw <2 x i8> %y, %z
+ %r = srem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, <i8 0, i8 poison>
+ ret <2 x i1> %c
+}
+
+define <2 x i1> @icmp_eq_srem_mul_vec_non_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_srem_mul_vec_non_splat(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], <i8 0, i8 -1>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nsw <2 x i8> %x, %z
+ %b = mul nsw <2 x i8> %y, %z
+ %r = srem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, <i8 0, i8 -1>
+ ret <2 x i1> %c
+}
+
+define i1 @icmp_eq_srem_mul_negative_flags1(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_negative_flags1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul i8 %x, %z
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_negative_flags2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_negative_flags2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_negative_common_op(i8 %x, i8 %y, i8 %u, i8 %v) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_negative_common_op(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[U:%.*]], i8 [[V:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[U]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[V]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %u
+ %b = mul nsw i8 %y, %v
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_negative_multi_use(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_negative_multi_use(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i8 [[R]])
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ call void @use(i8 %r)
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_srem_mul_negative_wrong_constant(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_srem_mul_negative_wrong_constant(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], -1
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nsw i8 %x, %z
+ %b = mul nsw i8 %y, %z
+ %r = srem i8 %a, %b
+ %c = icmp eq i8 %r, -1
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %z, %x
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %z, %y
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_commuted3(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted3(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %z, %x
+ %b = mul nuw i8 %z, %y
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_multi_use(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: call void @use(i8 [[A]])
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: call void @use(i8 [[B]])
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ call void @use(i8 %a)
+ %b = mul nuw i8 %y, %z
+ call void @use(i8 %b)
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_ne_urem_mul(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_ne_urem_mul(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp ne i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_const1(i8 %x, i8 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], 3
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], 3
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, 3
+ %b = mul nuw i8 %y, 3
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_const2(i8 %x, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], 3
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %z, 3
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_const3(i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const3(
+; CHECK-SAME: i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], 3
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %z, 3
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define <2 x i1> @icmp_eq_urem_mul_vec_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_urem_mul_vec_splat(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nuw <2 x i8> %x, %z
+ %b = mul nuw <2 x i8> %y, %z
+ %r = urem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, zeroinitializer
+ ret <2 x i1> %c
+}
+
+define <2 x i1> @icmp_eq_urem_mul_vec_splat_poison(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_urem_mul_vec_splat_poison(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], <i8 0, i8 poison>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nuw <2 x i8> %x, %z
+ %b = mul nuw <2 x i8> %y, %z
+ %r = urem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, <i8 0, i8 poison>
+ ret <2 x i1> %c
+}
+
+define <2 x i1> @icmp_eq_urem_mul_vec_non_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: define <2 x i1> @icmp_eq_urem_mul_vec_non_splat(
+; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw <2 x i8> [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], <i8 0, i8 1>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %a = mul nuw <2 x i8> %x, %z
+ %b = mul nuw <2 x i8> %y, %z
+ %r = urem <2 x i8> %a, %b
+ %c = icmp eq <2 x i8> %r, <i8 0, i8 1>
+ ret <2 x i1> %c
+}
+
+define i1 @icmp_eq_urem_mul_negative_flags1(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_negative_flags1(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul i8 %x, %z
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_negative_flags2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_negative_flags2(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_negative_common_op(i8 %x, i8 %y, i8 %u, i8 %v) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_negative_common_op(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[U:%.*]], i8 [[V:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[U]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[V]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %u
+ %b = mul nuw i8 %y, %v
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_negative_multi_use(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_negative_multi_use(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i8 [[R]])
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ call void @use(i8 %r)
+ %c = icmp eq i8 %r, 0
+ ret i1 %c
+}
+
+define i1 @icmp_eq_urem_mul_negative_wrong_constant(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i1 @icmp_eq_urem_mul_negative_wrong_constant(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
+; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 1
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %a = mul nuw i8 %x, %z
+ %b = mul nuw i8 %y, %z
+ %r = urem i8 %a, %b
+ %c = icmp eq i8 %r, 1
+ ret i1 %c
+}
+
>From d1edd2480e53fce0888978414e78ae2853212ab3 Mon Sep 17 00:00:00 2001
From: Ashish Ahuja <shivashish.ahuja at gmail.com>
Date: Wed, 10 Dec 2025 22:07:46 +0530
Subject: [PATCH 2/2] [InstCombine] Add fold '(xz rem yz) == 0 -> (x rem y) ==
0'
---
.../InstCombine/InstCombineCompares.cpp | 59 ++++++++++++++
.../InstCombine/InstCombineInternal.h | 2 +
llvm/test/Transforms/InstCombine/icmp-rem.ll | 76 +++++--------------
3 files changed, 81 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index abf4381ebd794..729fa86c5a801 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2735,6 +2735,61 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
return new ICmpInst(ICmpInst::ICMP_UGT, And, ConstantInt::get(Ty, SignMask));
}
+/// Fold icmp {eq, ne} ({us}rem (mul n{us}w XZ, YZ)), 0 ->
+/// icmp {eq, ne} ({us}rem (mul n{us}w X, Y)), 0
+Instruction *InstCombinerImpl::foldICmpRemConstant(ICmpInst &Cmp,
+ BinaryOperator *Rem,
+ const APInt &C) {
+ assert((Rem->getOpcode() == Instruction::SRem ||
+ Rem->getOpcode() == Instruction::URem) &&
+ "foldICmpRemConstant is only for srem/urem.");
+
+ if (!C.isZero() || !Rem->hasOneUse())
+ return nullptr;
+
+ const ICmpInst::Predicate Pred = Cmp.getPredicate();
+ if (Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
+ return nullptr;
+
+ Value *Dividend = Rem->getOperand(0);
+ Value *Divisor = Rem->getOperand(1);
+
+ Value *X, *Y, *Z;
+ Value *NewRem;
+ if (Rem->getOpcode() == Instruction::SRem) {
+ if (!match(Dividend, m_NSWMul(m_Value(X), m_Value(Z))))
+ return nullptr;
+
+ // m_c_NSWMul does not exist
+ if (!match(Divisor, m_NSWMul(m_Value(Y), m_Specific(Z))) &&
+ !match(Divisor, m_NSWMul(m_Specific(Z), m_Value(Y)))) {
+ std::swap(X, Z);
+ if (!match(Divisor, m_NSWMul(m_Value(Y), m_Specific(Z))) &&
+ !match(Divisor, m_NSWMul(m_Specific(Z), m_Value(Y))))
+ return nullptr;
+ }
+
+ NewRem = Builder.CreateSRem(X, Y);
+ } else if (Rem->getOpcode() == Instruction::URem) {
+ if (!match(Dividend, m_NUWMul(m_Value(X), m_Value(Z))))
+ return nullptr;
+
+ // m_c_NUWMul does not exist
+ if (!match(Divisor, m_NUWMul(m_Value(Y), m_Specific(Z))) &&
+ !match(Divisor, m_NUWMul(m_Specific(Z), m_Value(Y)))) {
+ std::swap(X, Z);
+ if (!match(Divisor, m_NUWMul(m_Value(Y), m_Specific(Z))) &&
+ !match(Divisor, m_NUWMul(m_Specific(Z), m_Value(Y))))
+ return nullptr;
+ }
+
+ NewRem = Builder.CreateURem(X, Y);
+ }
+
+ Type *Ty = Rem->getType();
+ return new ICmpInst(Pred, NewRem, ConstantInt::getNullValue(Ty));
+}
+
/// Fold icmp (udiv X, Y), C.
Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp,
BinaryOperator *UDiv,
@@ -4009,6 +4064,10 @@ Instruction *InstCombinerImpl::foldICmpBinOpWithConstant(ICmpInst &Cmp,
case Instruction::SRem:
if (Instruction *I = foldICmpSRemConstant(Cmp, BO, C))
return I;
+ [[fallthrough]];
+ case Instruction::URem:
+ if (Instruction *I = foldICmpRemConstant(Cmp, BO, C))
+ return I;
break;
case Instruction::UDiv:
if (Instruction *I = foldICmpUDivConstant(Cmp, BO, C))
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 9bdd8cb71f7f3..de6d2ec3ac356 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -758,6 +758,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
const APInt &C);
Instruction *foldICmpSRemConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
const APInt &C);
+ Instruction *foldICmpRemConstant(ICmpInst &Cmp, BinaryOperator *Rem,
+ const APInt &C);
Instruction *foldICmpUDivConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
const APInt &C);
Instruction *foldICmpDivConstant(ICmpInst &Cmp, BinaryOperator *Div,
diff --git a/llvm/test/Transforms/InstCombine/icmp-rem.ll b/llvm/test/Transforms/InstCombine/icmp-rem.ll
index 93d5aae524467..6e1fbb89ad0ca 100644
--- a/llvm/test/Transforms/InstCombine/icmp-rem.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-rem.ll
@@ -6,9 +6,7 @@ declare void @use(i8)
define i1 @icmp_eq_srem_mul(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -22,9 +20,7 @@ define i1 @icmp_eq_srem_mul(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_srem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], [[X]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -38,9 +34,7 @@ define i1 @icmp_eq_srem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_srem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted2(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], [[Y]]
-; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -54,9 +48,7 @@ define i1 @icmp_eq_srem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_srem_mul_commuted3(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_commuted3(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], [[X]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], [[Y]]
-; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -74,7 +66,7 @@ define i1 @icmp_eq_srem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
; CHECK-NEXT: call void @use(i8 [[A]])
; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i8 [[B]])
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -90,9 +82,7 @@ define i1 @icmp_eq_srem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_ne_srem_mul(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_ne_srem_mul(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -106,9 +96,7 @@ define i1 @icmp_ne_srem_mul(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_srem_mul_const1(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], -2
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], -2
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -122,9 +110,7 @@ define i1 @icmp_eq_srem_mul_const1(i8 %x, i8 %y) {
define i1 @icmp_eq_srem_mul_const2(i8 %x, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const2(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Z]], -3
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[X]], 3
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -138,9 +124,7 @@ define i1 @icmp_eq_srem_mul_const2(i8 %x, i8 %z) {
define i1 @icmp_eq_srem_mul_const3(i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_srem_mul_const3(
; CHECK-SAME: i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[Z]], -3
-; CHECK-NEXT: [[B:%.*]] = mul nsw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = srem i8 -3, [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -154,9 +138,7 @@ define i1 @icmp_eq_srem_mul_const3(i8 %y, i8 %z) {
define <2 x i1> @icmp_eq_srem_mul_vec_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: define <2 x i1> @icmp_eq_srem_mul_vec_splat(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nsw <2 x i8> [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nsw <2 x i8> [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[C]]
;
@@ -284,9 +266,7 @@ define i1 @icmp_eq_srem_mul_negative_wrong_constant(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_urem_mul(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -300,9 +280,7 @@ define i1 @icmp_eq_urem_mul(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_urem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], [[X]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -316,9 +294,7 @@ define i1 @icmp_eq_urem_mul_commuted1(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_urem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted2(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -332,9 +308,7 @@ define i1 @icmp_eq_urem_mul_commuted2(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_urem_mul_commuted3(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_commuted3(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], [[X]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -352,7 +326,7 @@ define i1 @icmp_eq_urem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
; CHECK-NEXT: call void @use(i8 [[A]])
; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i8 [[B]])
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -368,9 +342,7 @@ define i1 @icmp_eq_urem_mul_multi_use(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_ne_urem_mul(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_ne_urem_mul(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -384,9 +356,7 @@ define i1 @icmp_ne_urem_mul(i8 %x, i8 %y, i8 %z) {
define i1 @icmp_eq_urem_mul_const1(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], 3
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], 3
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -400,9 +370,7 @@ define i1 @icmp_eq_urem_mul_const1(i8 %x, i8 %y) {
define i1 @icmp_eq_urem_mul_const2(i8 %x, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const2(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Z]], 3
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[X]], 3
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -416,9 +384,7 @@ define i1 @icmp_eq_urem_mul_const2(i8 %x, i8 %z) {
define i1 @icmp_eq_urem_mul_const3(i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @icmp_eq_urem_mul_const3(
; CHECK-SAME: i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[Z]], 3
-; CHECK-NEXT: [[B:%.*]] = mul nuw i8 [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 3, [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[R]], 0
; CHECK-NEXT: ret i1 [[C]]
;
@@ -432,9 +398,7 @@ define i1 @icmp_eq_urem_mul_const3(i8 %y, i8 %z) {
define <2 x i1> @icmp_eq_urem_mul_vec_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: define <2 x i1> @icmp_eq_urem_mul_vec_splat(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]]) {
-; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[X]], [[Z]]
-; CHECK-NEXT: [[B:%.*]] = mul nuw <2 x i8> [[Y]], [[Z]]
-; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> [[X]], [[Y]]
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[R]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[C]]
;
More information about the llvm-commits
mailing list