[InstCombine] Handle constant arms in select of srem fold

Extend folding for `2^n` euclidean division remainder operations
on signed integers by handling the specific instance in which one
`select` arm has already been replaced by 1.

Reported-By: HypheX

Fixes: https://github.com/llvm/llvm-project/issues/66417.
This commit is contained in:
Antonio Frighetto 2023-09-16 12:11:10 +02:00
parent 5163319ee2
commit ce5b88bf10
2 changed files with 44 additions and 9 deletions

View File

@ -2616,20 +2616,33 @@ static Instruction *foldSelectWithSRem(SelectInst &SI, InstCombinerImpl &IC,
if (!TrueIfSigned)
std::swap(TrueVal, FalseVal);
// We are matching a quite specific pattern here:
auto FoldToBitwiseAnd = [&](Value *Remainder) -> Instruction * {
Value *Add = Builder.CreateAdd(
Remainder, Constant::getAllOnesValue(RemRes->getType()));
return BinaryOperator::CreateAnd(Op, Add);
};
// Match the general case:
// %rem = srem i32 %x, %n
// %cnd = icmp slt i32 %rem, 0
// %add = add i32 %rem, %n
// %sel = select i1 %cnd, i32 %add, i32 %rem
if (!(match(TrueVal, m_Add(m_Value(RemRes), m_Value(Remainder))) &&
match(RemRes, m_SRem(m_Value(Op), m_Specific(Remainder))) &&
IC.isKnownToBeAPowerOfTwo(Remainder, /*OrZero*/ true) &&
FalseVal == RemRes))
return nullptr;
if (match(TrueVal, m_Add(m_Value(RemRes), m_Value(Remainder))) &&
match(RemRes, m_SRem(m_Value(Op), m_Specific(Remainder))) &&
IC.isKnownToBeAPowerOfTwo(Remainder, /*OrZero*/ true) &&
FalseVal == RemRes)
return FoldToBitwiseAnd(Remainder);
Value *Add = Builder.CreateAdd(Remainder,
Constant::getAllOnesValue(RemRes->getType()));
return BinaryOperator::CreateAnd(Op, Add);
// Match the case where the one arm has been replaced by constant 1:
// %rem = srem i32 %n, 2
// %cnd = icmp slt i32 %rem, 0
// %sel = select i1 %cnd, i32 1, i32 %rem
if (match(TrueVal, m_One()) &&
match(RemRes, m_SRem(m_Value(Op), m_SpecificInt(2))) &&
FalseVal == RemRes)
return FoldToBitwiseAnd(ConstantInt::get(RemRes->getType(), 2));
return nullptr;
}
static Value *foldSelectWithFrozenICmp(SelectInst &Sel, InstCombiner::BuilderTy &Builder) {

View File

@ -321,3 +321,25 @@ define i8 @rem_euclid_non_const_pow2(i8 %0, i8 %1) {
%sel = select i1 %cond, i8 %add, i8 %rem
ret i8 %sel
}
define i32 @rem_euclid_pow2_true_arm_folded(i32 %n) {
; CHECK-LABEL: @rem_euclid_pow2_true_arm_folded(
; CHECK-NEXT: [[RES:%.*]] = and i32 [[N:%.*]], 1
; CHECK-NEXT: ret i32 [[RES]]
;
%rem = srem i32 %n, 2
%neg = icmp slt i32 %rem, 0
%res = select i1 %neg, i32 1, i32 %rem
ret i32 %res
}
define i32 @rem_euclid_pow2_false_arm_folded(i32 %n) {
; CHECK-LABEL: @rem_euclid_pow2_false_arm_folded(
; CHECK-NEXT: [[RES:%.*]] = and i32 [[N:%.*]], 1
; CHECK-NEXT: ret i32 [[RES]]
;
%rem = srem i32 %n, 2
%nonneg = icmp sge i32 %rem, 0
%res = select i1 %nonneg, i32 %rem, i32 1
ret i32 %res
}