[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