Skip to content

Commit d94958b

Browse files
authored
[InstCombine] Fold icmp samesign u{gt/lt} (X +nsw C2), C -> icmp s{gt/lt} X, (C - C2) (#169960)
Fixes #166973 Partially addresses #134028 Alive2 proof: https://alive2.llvm.org/ce/z/BqHQNN
1 parent 3a6781e commit d94958b

File tree

2 files changed

+93
-10
lines changed

2 files changed

+93
-10
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3132,7 +3132,7 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
31323132

31333133
Value *Op0, *Op1;
31343134
Instruction *Ext0, *Ext1;
3135-
const CmpInst::Predicate Pred = Cmp.getPredicate();
3135+
const CmpPredicate Pred = Cmp.getCmpPredicate();
31363136
if (match(Add,
31373137
m_Add(m_CombineAnd(m_Instruction(Ext0), m_ZExtOrSExt(m_Value(Op0))),
31383138
m_CombineAnd(m_Instruction(Ext1),
@@ -3167,22 +3167,29 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
31673167

31683168
// If the add does not wrap, we can always adjust the compare by subtracting
31693169
// the constants. Equality comparisons are handled elsewhere. SGE/SLE/UGE/ULE
3170-
// are canonicalized to SGT/SLT/UGT/ULT.
3171-
if ((Add->hasNoSignedWrap() &&
3172-
(Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT)) ||
3173-
(Add->hasNoUnsignedWrap() &&
3174-
(Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT))) {
3170+
// have been canonicalized to SGT/SLT/UGT/ULT.
3171+
if (Add->hasNoUnsignedWrap() &&
3172+
(Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT)) {
31753173
bool Overflow;
3176-
APInt NewC =
3177-
Cmp.isSigned() ? C.ssub_ov(*C2, Overflow) : C.usub_ov(*C2, Overflow);
3174+
APInt NewC = C.usub_ov(*C2, Overflow);
31783175
// If there is overflow, the result must be true or false.
3179-
// TODO: Can we assert there is no overflow because InstSimplify always
3180-
// handles those cases?
31813176
if (!Overflow)
31823177
// icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2)
31833178
return new ICmpInst(Pred, X, ConstantInt::get(Ty, NewC));
31843179
}
31853180

3181+
CmpInst::Predicate ChosenPred = Pred.getPreferredSignedPredicate();
3182+
3183+
if (Add->hasNoSignedWrap() &&
3184+
(ChosenPred == ICmpInst::ICMP_SGT || ChosenPred == ICmpInst::ICMP_SLT)) {
3185+
bool Overflow;
3186+
APInt NewC = C.ssub_ov(*C2, Overflow);
3187+
if (!Overflow)
3188+
// icmp samesign ugt/ult (add nsw X, C2), C
3189+
// -> icmp sgt/slt X, (C - C2)
3190+
return new ICmpInst(ChosenPred, X, ConstantInt::get(Ty, NewC));
3191+
}
3192+
31863193
if (ICmpInst::isUnsigned(Pred) && Add->hasNoSignedWrap() &&
31873194
C.isNonNegative() && (C - *C2).isNonNegative() &&
31883195
computeConstantRange(X, /*ForSigned=*/true).add(*C2).isAllNonNegative())

llvm/test/Transforms/InstCombine/icmp-add.ll

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,3 +3440,79 @@ define i1 @val_is_aligend_pred_mismatch(i32 %num) {
34403440
%_0 = icmp sge i32 %num.masked, %num
34413441
ret i1 %_0
34423442
}
3443+
3444+
define i1 @icmp_samesign_with_nsw_add(i32 %arg0) {
3445+
; CHECK-LABEL: @icmp_samesign_with_nsw_add(
3446+
; CHECK-NEXT: entry:
3447+
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[ARG0:%.*]], 25
3448+
; CHECK-NEXT: ret i1 [[V1]]
3449+
;
3450+
entry:
3451+
%v0 = add nsw i32 %arg0, -18
3452+
%v1 = icmp samesign ugt i32 %v0, 7
3453+
ret i1 %v1
3454+
}
3455+
3456+
; Negative test; Fold shouldn't fire since -124 - 12 causes signed overflow
3457+
define i1 @icmp_samesign_with_nsw_add_neg(i8 %arg0) {
3458+
; CHECK-LABEL: @icmp_samesign_with_nsw_add_neg(
3459+
; CHECK-NEXT: entry:
3460+
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[ARG0:%.*]], -121
3461+
; CHECK-NEXT: [[V1:%.*]] = icmp ult i8 [[TMP0]], 123
3462+
; CHECK-NEXT: ret i1 [[V1]]
3463+
;
3464+
entry:
3465+
%v0 = add nsw i8 %arg0, 12
3466+
%v1 = icmp samesign ugt i8 %v0, -124
3467+
ret i1 %v1
3468+
}
3469+
3470+
define i1 @icmp_with_nuw_add(i32 %arg0) {
3471+
; CHECK-LABEL: @icmp_with_nuw_add(
3472+
; CHECK-NEXT: entry:
3473+
; CHECK-NEXT: [[V1:%.*]] = icmp ult i32 [[ARG0:%.*]], 11
3474+
; CHECK-NEXT: ret i1 [[V1]]
3475+
;
3476+
entry:
3477+
%v0 = add nuw i32 %arg0, 7
3478+
%v1 = icmp ult i32 %v0, 18
3479+
ret i1 %v1
3480+
}
3481+
3482+
define i1 @icmp_partial_negative_samesign_ult_to_slt(i8 range(i8 -1, 5) %x) {
3483+
; CHECK-LABEL: @icmp_partial_negative_samesign_ult_to_slt(
3484+
; CHECK-NEXT: entry:
3485+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 2
3486+
; CHECK-NEXT: ret i1 [[CMP]]
3487+
;
3488+
entry:
3489+
%add = add nsw i8 %x, -5
3490+
%cmp = icmp samesign ult i8 %add, -3
3491+
ret i1 %cmp
3492+
}
3493+
3494+
define i1 @icmp_pos_samesign_slt_to_ult(i8 range(i8 1, 5) %x) {
3495+
; CHECK-LABEL: @icmp_pos_samesign_slt_to_ult(
3496+
; CHECK-NEXT: entry:
3497+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i8 [[X:%.*]], 2
3498+
; CHECK-NEXT: ret i1 [[CMP]]
3499+
;
3500+
entry:
3501+
%add = add nsw i8 %x, 1
3502+
%cmp = icmp samesign slt i8 %add, 3
3503+
ret i1 %cmp
3504+
}
3505+
3506+
; Since higher priority is given to unsigned predicates, the predicate should
3507+
; not change
3508+
define i1 @icmp_nuw_nsw_samesign(i32 %arg0) {
3509+
; CHECK-LABEL: @icmp_nuw_nsw_samesign(
3510+
; CHECK-NEXT: entry:
3511+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ARG0:%.*]], 9
3512+
; CHECK-NEXT: ret i1 [[CMP]]
3513+
;
3514+
entry:
3515+
%v0 = add nuw nsw i32 %arg0, 1
3516+
%cmp = icmp samesign ult i32 %v0, 10
3517+
ret i1 %cmp
3518+
}

0 commit comments

Comments
 (0)