forked from OSchip/llvm-project
[InstCombine] Fold srem(X, PowerOf2) == C into (X & Mask) == C for positive C
This diff extends InstCombinerImpl::foldICmpSRemConstant to handle the cases srem(X, PowerOf2) == C and srem(X, PowerOf2) != C for positive C. This addresses the issue https://github.com/llvm/llvm-project/issues/54650 Differential revision: https://reviews.llvm.org/D122942 Test plan: make check-all
This commit is contained in:
parent
911cfcd7f5
commit
6cf10b7e6e
|
@ -2335,7 +2335,8 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
|
|||
// constant power-of-2 value:
|
||||
// (X % pow2C) sgt/slt 0
|
||||
const ICmpInst::Predicate Pred = Cmp.getPredicate();
|
||||
if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT)
|
||||
if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT &&
|
||||
Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
|
||||
return nullptr;
|
||||
|
||||
// TODO: The one-use check is standard because we do not typically want to
|
||||
|
@ -2345,7 +2346,15 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
|
|||
return nullptr;
|
||||
|
||||
const APInt *DivisorC;
|
||||
if (!C.isZero() || !match(SRem->getOperand(1), m_Power2(DivisorC)))
|
||||
if (!match(SRem->getOperand(1), m_Power2(DivisorC)))
|
||||
return nullptr;
|
||||
|
||||
// For cmp_sgt/cmp_slt only zero valued C is handled.
|
||||
// For cmp_eq/cmp_ne only positive valued C is handled.
|
||||
if (((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) &&
|
||||
!C.isZero()) ||
|
||||
((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
|
||||
!C.isStrictlyPositive()))
|
||||
return nullptr;
|
||||
|
||||
// Mask off the sign bit and the modulo bits (low-bits).
|
||||
|
@ -2354,6 +2363,9 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
|
|||
Constant *MaskC = ConstantInt::get(Ty, SignMask | (*DivisorC - 1));
|
||||
Value *And = Builder.CreateAnd(SRem->getOperand(0), MaskC);
|
||||
|
||||
if (Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE)
|
||||
return new ICmpInst(Pred, And, ConstantInt::get(Ty, C));
|
||||
|
||||
// For 'is positive?' check that the sign-bit is clear and at least 1 masked
|
||||
// bit is set. Example:
|
||||
// (i8 X % 32) s> 0 --> (X & 159) s> 0
|
||||
|
|
|
@ -742,7 +742,7 @@ define i1 @test28(i32 %A) {
|
|||
|
||||
define i1 @positive_and_odd_eq(i32 %A) {
|
||||
; CHECK-LABEL: @positive_and_odd_eq(
|
||||
; CHECK-NEXT: [[B:%.*]] = srem i32 [[A:%.*]], 2
|
||||
; CHECK-NEXT: [[B:%.*]] = and i32 [[A:%.*]], -2147483647
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[B]], 1
|
||||
; CHECK-NEXT: ret i1 [[C]]
|
||||
;
|
||||
|
@ -764,7 +764,7 @@ define i1 @negative_and_odd_eq(i32 %A) {
|
|||
|
||||
define i1 @positive_and_odd_ne(i32 %A) {
|
||||
; CHECK-LABEL: @positive_and_odd_ne(
|
||||
; CHECK-NEXT: [[B:%.*]] = srem i32 [[A:%.*]], 2
|
||||
; CHECK-NEXT: [[B:%.*]] = and i32 [[A:%.*]], -2147483647
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[B]], 1
|
||||
; CHECK-NEXT: ret i1 [[C]]
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue