Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3132,7 +3132,7 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,

Value *Op0, *Op1;
Instruction *Ext0, *Ext1;
const CmpInst::Predicate Pred = Cmp.getPredicate();
const CmpPredicate Pred(Cmp.getCmpPredicate());
if (match(Add,
m_Add(m_CombineAnd(m_Instruction(Ext0), m_ZExtOrSExt(m_Value(Op0))),
m_CombineAnd(m_Instruction(Ext1),
Expand Down Expand Up @@ -3167,20 +3167,21 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,

// If the add does not wrap, we can always adjust the compare by subtracting
// the constants. Equality comparisons are handled elsewhere. SGE/SLE/UGE/ULE
// are canonicalized to SGT/SLT/UGT/ULT.
if ((Add->hasNoSignedWrap() &&
(Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT)) ||
(Add->hasNoUnsignedWrap() &&
(Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT))) {
// has been canonicalized to SGT/SLT/UGT/ULT.
CmpInst::Predicate ChosenPred = Pred.getPreferredSignedPredicate();
if ((Add->hasNoSignedWrap() && (ChosenPred == ICmpInst::ICMP_SGT ||
ChosenPred == ICmpInst::ICMP_SLT)) ||
(Add->hasNoUnsignedWrap() && (ChosenPred == ICmpInst::ICMP_UGT ||
ChosenPred == ICmpInst::ICMP_ULT))) {
bool Overflow;
APInt NewC =
Cmp.isSigned() ? C.ssub_ov(*C2, Overflow) : C.usub_ov(*C2, Overflow);
APInt NewC = ICmpInst::isSigned(ChosenPred) ? C.ssub_ov(*C2, Overflow)
: C.usub_ov(*C2, Overflow);
// If there is overflow, the result must be true or false.
// TODO: Can we assert there is no overflow because InstSimplify always
// handles those cases?
Comment on lines 3180 to 3181
Copy link
Contributor Author

@wermos wermos Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this comment be removed? If I understood this comment correctly, then it is obvious that there are cases where an overflow can happen, so this defensive code is needed. Specifically, the @icmp_samesign_with_nsw_add_neg test causes a ssub overflow to happen.

if (!Overflow)
// icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2)
return new ICmpInst(Pred, X, ConstantInt::get(Ty, NewC));
return new ICmpInst(ChosenPred, X, ConstantInt::get(Ty, NewC));
}

if (ICmpInst::isUnsigned(Pred) && Add->hasNoSignedWrap() &&
Expand Down
62 changes: 62 additions & 0 deletions llvm/test/Transforms/InstCombine/icmp-add.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3440,3 +3440,65 @@ define i1 @val_is_aligend_pred_mismatch(i32 %num) {
%_0 = icmp sge i32 %num.masked, %num
ret i1 %_0
}

define i1 @icmp_samesign_with_nsw_add(i32 %arg0) {
; CHECK-LABEL: @icmp_samesign_with_nsw_add(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[ARG0:%.*]], 25
; CHECK-NEXT: ret i1 [[V1]]
;
entry:
%v0 = add nsw i32 %arg0, -18
%v1 = icmp samesign ugt i32 %v0, 7
ret i1 %v1
}

; Negative test; Fold shouldn't fire since -124 - 12 causes signed overflow
define i1 @icmp_samesign_with_nsw_add_neg(i8 %arg0) {
; CHECK-LABEL: @icmp_samesign_with_nsw_add_neg(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[ARG0:%.*]], -121
; CHECK-NEXT: [[V1:%.*]] = icmp ult i8 [[TMP0]], 123
; CHECK-NEXT: ret i1 [[V1]]
;
entry:
%v0 = add nsw i8 %arg0, 12
%v1 = icmp samesign ugt i8 %v0, -124
ret i1 %v1
}

define i1 @icmp_with_nuw_add(i32 %arg0) {
; CHECK-LABEL: @icmp_with_nuw_add(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V1:%.*]] = icmp ult i32 [[ARG0:%.*]], 11
; CHECK-NEXT: ret i1 [[V1]]
;
entry:
%v0 = add nuw i32 %arg0, 7
%v1 = icmp ult i32 %v0, 18
ret i1 %v1
}

define i1 @icmp_partial_negative_samesign_ult_to_slt(i8 range(i8 -1, 5) %x) {
; CHECK-LABEL: @icmp_partial_negative_samesign_ult_to_slt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%add = add nsw i8 %x, -5
%cmp = icmp samesign ult i8 %add, -3
ret i1 %cmp
}

define i1 @icmp_pos_samesign_slt_to_ult(i8 range(i8 1, 5) %x) {
; CHECK-LABEL: @icmp_pos_samesign_slt_to_ult(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i8 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%add = add nsw i8 %x, 1
%cmp = icmp samesign slt i8 %add, 3
ret i1 %cmp
}
Loading