Skip to content

Commit ccc9c7d

Browse files
committed
[InstCombine] fold unsigned predicates to signed on srem result
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/2msAMA Proof for the test cases: https://alive2.llvm.org/ce/z/M_PBjw
1 parent d84b865 commit ccc9c7d

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
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 % DivisorC) ugt C -> (X % DivisorC) slt 0
2681+
// iff abs(DivisorC) ule (C slt 0 ? ~C : C)+1
2682+
// (X % DivisorC) ult C+1 -> (X % DivisorC) sgt -1
2683+
// iff abs(DivisorC) ule (C+1 slt 0 ? ~C : C)+1
2684+
2685+
const APInt *DivisorC;
2686+
if (!match(SRem->getOperand(1), m_APInt(DivisorC)))
2687+
return nullptr;
2688+
2689+
APInt NormalizedC = C;
2690+
assert(!NormalizedC.isZero() &&
2691+
"srem X, 0 should have been simplified already.");
2692+
if (Pred == ICmpInst::ICMP_ULT)
2693+
--NormalizedC;
2694+
if (C.isNegative())
2695+
NormalizedC.flipAllBits();
2696+
assert(!NormalizedC.isMaxValue() &&
2697+
"srem i1 X, -1 should have been simplified already.");
2698+
++NormalizedC;
2699+
if (!DivisorC->abs().ule(NormalizedC))
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: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,11 +3020,7 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
30203020

30213021
define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
30223022
; CHECK-LABEL: @floor_sdiv_using_srem_by_8(
3023-
; CHECK-NEXT: [[D:%.*]] = sdiv i32 [[X:%.*]], 8
3024-
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 8
3025-
; CHECK-NEXT: [[I:%.*]] = icmp ugt i32 [[R]], -2147483648
3026-
; CHECK-NEXT: [[S:%.*]] = sext i1 [[I]] to i32
3027-
; CHECK-NEXT: [[F:%.*]] = add nsw i32 [[D]], [[S]]
3023+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 3
30283024
; CHECK-NEXT: ret i32 [[F]]
30293025
;
30303026
%d = sdiv i32 %x, 8
@@ -3037,11 +3033,7 @@ define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
30373033

30383034
define i32 @floor_sdiv_using_srem_by_2(i32 %x) {
30393035
; CHECK-LABEL: @floor_sdiv_using_srem_by_2(
3040-
; CHECK-NEXT: [[D:%.*]] = sdiv i32 [[X:%.*]], 2
3041-
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2
3042-
; CHECK-NEXT: [[I:%.*]] = icmp ugt i32 [[R]], -2147483648
3043-
; CHECK-NEXT: [[S:%.*]] = sext i1 [[I]] to i32
3044-
; CHECK-NEXT: [[F:%.*]] = add nsw i32 [[D]], [[S]]
3036+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 1
30453037
; CHECK-NEXT: ret i32 [[F]]
30463038
;
30473039
%d = sdiv i32 %x, 2

0 commit comments

Comments
 (0)