[llvm] [InstCombine] Add fold `(x * z) % (y * z) == 0` -> `x % y == 0` (PR #171655)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 10 09:38:53 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Ashish Ahuja (double-fault)
<details>
<summary>Changes</summary>
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
---
Patch is 21.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/171655.diff
3 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+59)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineInternal.h (+2)
- (added) llvm/test/Transforms/InstCombine/icmp-rem.ll (+525)
``````````diff
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
new file mode 100644
index 0000000000000..6e1fbb89ad0ca
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-rem.ll
@@ -0,0 +1,525 @@
+; 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: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
+; 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: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
+; 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: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
+; 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: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
+; 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 [[X]], [[Y]]
+; 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: [[TMP1:%.*]] = srem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = srem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = srem i8 [[X]], 3
+; 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: [[R:%.*]] = srem i8 -3, [[Y]]
+; 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: [[R:%.*]] = srem <2 x i8> [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], [[Y]]
+; 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: [[R:%.*]] = urem i8 [[X]], 3
+; 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: [[R:%.*]] = urem i8 3, [[Y]]
+; 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: [[R:%.*]] = urem <2 x i8> [[X]], [[Y]]
+; 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: ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/171655
More information about the llvm-commits
mailing list