Skip to content

Commit bb59eb8

Browse files
authored
[InstCombine] fold unsigned predicates on srem result (#122520)
This allows optimization of more signed floor implementations when the divisor is a known power of two to an arithmetic shift. Proof for the implemented optimizations: https://alive2.llvm.org/ce/z/j6C-Nz Proof for the test cases: https://alive2.llvm.org/ce/z/M_PBjw --------- Co-authored-by: Jacob Young <[email protected]>
1 parent 4233a15 commit bb59eb8

File tree

3 files changed

+442
-1
lines changed

3 files changed

+442
-1
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2674,10 +2674,41 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp,
26742674
Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
26752675
BinaryOperator *SRem,
26762676
const APInt &C) {
2677+
const ICmpInst::Predicate Pred = Cmp.getPredicate();
2678+
if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT) {
2679+
// Canonicalize unsigned predicates to signed:
2680+
// (X s% DivisorC) u> C -> (X s% DivisorC) s< 0
2681+
// iff (C s< 0 ? ~C : C) u>= abs(DivisorC)-1
2682+
// (X s% DivisorC) u< C+1 -> (X s% DivisorC) s> -1
2683+
// iff (C+1 s< 0 ? ~C : C) u>= abs(DivisorC)-1
2684+
2685+
const APInt *DivisorC;
2686+
if (!match(SRem->getOperand(1), m_APInt(DivisorC)))
2687+
return nullptr;
2688+
2689+
APInt NormalizedC = C;
2690+
if (Pred == ICmpInst::ICMP_ULT) {
2691+
assert(!NormalizedC.isZero() &&
2692+
"ult X, 0 should have been simplified already.");
2693+
--NormalizedC;
2694+
}
2695+
if (C.isNegative())
2696+
NormalizedC.flipAllBits();
2697+
assert(!DivisorC->isZero() &&
2698+
"srem X, 0 should have been simplified already.");
2699+
if (!NormalizedC.uge(DivisorC->abs() - 1))
2700+
return nullptr;
2701+
2702+
Type *Ty = SRem->getType();
2703+
if (Pred == ICmpInst::ICMP_UGT)
2704+
return new ICmpInst(ICmpInst::ICMP_SLT, SRem,
2705+
ConstantInt::getNullValue(Ty));
2706+
return new ICmpInst(ICmpInst::ICMP_SGT, SRem,
2707+
ConstantInt::getAllOnesValue(Ty));
2708+
}
26772709
// Match an 'is positive' or 'is negative' comparison of remainder by a
26782710
// constant power-of-2 value:
26792711
// (X % pow2C) sgt/slt 0
2680-
const ICmpInst::Predicate Pred = Cmp.getPredicate();
26812712
if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT &&
26822713
Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
26832714
return nullptr;

llvm/test/Transforms/InstCombine/add.ll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,6 +3018,32 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
30183018
ret i32 %r
30193019
}
30203020

3021+
define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
3022+
; CHECK-LABEL: @floor_sdiv_using_srem_by_8(
3023+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 3
3024+
; CHECK-NEXT: ret i32 [[F]]
3025+
;
3026+
%d = sdiv i32 %x, 8
3027+
%r = srem i32 %x, 8
3028+
%i = icmp ugt i32 %r, -2147483648
3029+
%s = sext i1 %i to i32
3030+
%f = add i32 %d, %s
3031+
ret i32 %f
3032+
}
3033+
3034+
define i32 @floor_sdiv_using_srem_by_2(i32 %x) {
3035+
; CHECK-LABEL: @floor_sdiv_using_srem_by_2(
3036+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 1
3037+
; CHECK-NEXT: ret i32 [[F]]
3038+
;
3039+
%d = sdiv i32 %x, 2
3040+
%r = srem i32 %x, 2
3041+
%i = icmp ugt i32 %r, -2147483648
3042+
%s = sext i1 %i to i32
3043+
%f = add i32 %d, %s
3044+
ret i32 %f
3045+
}
3046+
30213047
; (X s>> (BW - 1)) + (zext (X s> 0)) --> (X s>> (BW - 1)) | (zext (X != 0))
30223048

30233049
define i8 @signum_i8_i8(i8 %x) {

0 commit comments

Comments
 (0)