Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
5 changes: 5 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,

computeKnownBits(Op0, DemandedElts, Known2, Q, Depth + 1);
KnownOut = KnownBits::computeForAddSub(Add, NSW, NUW, Known2, KnownOut);

if (!Add && NSW &&
isImpliedByDomCondition(ICmpInst::ICMP_SLE, Op1, Op0, Q.CxtI, Q.DL)
.value_or(false))
KnownOut.makeNonNegative();
}

static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
Expand Down
103 changes: 103 additions & 0 deletions llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please add a negative test with missing nsw flag?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare void @subroutine(i16)

define void @test_as_arg(i8 %a, i8 %b) {
; CHECK-LABEL: define void @test_as_arg(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
; CHECK: [[COND_FALSE]]:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg i8 [[SUB]] to i16
; CHECK-NEXT: call void @subroutine(i16 [[CONV]])
; CHECK-NEXT: br label %[[COND_END]]
; CHECK: [[COND_END]]:
; CHECK-NEXT: ret void
;
%cmp = icmp sgt i8 %a, %b
br i1 %cmp, label %cond.end, label %cond.false

cond.false:
%sub = sub nsw i8 %b, %a
%conv = sext i8 %sub to i16
call void @subroutine(i16 %conv)
br label %cond.end

cond.end:
ret void
}

define i16 @test_as_retval(i8 %a, i8 %b) {
; CHECK-LABEL: define i16 @test_as_retval(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
; CHECK: [[COND_TRUE]]:
; CHECK-NEXT: ret i16 0
; CHECK: [[COND_FALSE]]:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg i8 [[SUB]] to i16
; CHECK-NEXT: ret i16 [[CONV]]
;
%cmp = icmp sgt i8 %a, %b
br i1 %cmp, label %cond.true, label %cond.false

cond.true:
ret i16 0

cond.false:
%sub = sub nsw i8 %b, %a
%conv = sext i8 %sub to i16
ret i16 %conv
}

define void @test_as_arg_neg(i8 %a, i8 %b) {
; CHECK-LABEL: define void @test_as_arg_neg(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
; CHECK: [[COND_FALSE]]:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[SUB]] to i16
; CHECK-NEXT: call void @subroutine(i16 [[CONV]])
; CHECK-NEXT: br label %[[COND_END]]
; CHECK: [[COND_END]]:
; CHECK-NEXT: ret void
;
%cmp = icmp slt i8 %a, %b
br i1 %cmp, label %cond.end, label %cond.false

cond.false:
%sub = sub nsw i8 %b, %a
%conv = sext i8 %sub to i16
call void @subroutine(i16 %conv)
br label %cond.end

cond.end:
ret void
}

define i16 @test_as_retval_neg(i8 %a, i8 %b) {
; CHECK-LABEL: define i16 @test_as_retval_neg(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
; CHECK: [[COND_TRUE]]:
; CHECK-NEXT: ret i16 0
; CHECK: [[COND_FALSE]]:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[SUB]] to i16
; CHECK-NEXT: ret i16 [[CONV]]
;
%cmp = icmp slt i8 %a, %b
br i1 %cmp, label %cond.true, label %cond.false

cond.true:
ret i16 0

cond.false:
%sub = sub nsw i8 %b, %a
%conv = sext i8 %sub to i16
ret i16 %conv
}