-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LVI] Add trunc to i1 handling. #124480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LVI] Add trunc to i1 handling. #124480
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -398,6 +398,8 @@ class LazyValueInfoImpl { | |
std::optional<ValueLatticeElement> | ||
getValueFromICmpCondition(Value *Val, ICmpInst *ICI, bool isTrueDest, | ||
bool UseBlockValue); | ||
ValueLatticeElement getValueFromTrunc(Value *Val, TruncInst *Trunc, | ||
bool IsTrueDest); | ||
|
||
std::optional<ValueLatticeElement> | ||
getValueFromCondition(Value *Val, Value *Cond, bool IsTrueDest, | ||
|
@@ -1283,6 +1285,27 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition( | |
return ValueLatticeElement::getOverdefined(); | ||
} | ||
|
||
ValueLatticeElement LazyValueInfoImpl::getValueFromTrunc(Value *Val, | ||
TruncInst *Trunc, | ||
bool IsTrueDest) { | ||
assert(Trunc->getType()->isIntOrIntVectorTy(1)); | ||
|
||
if (Trunc->getOperand(0) != Val) | ||
return ValueLatticeElement::getOverdefined(); | ||
|
||
Type *Ty = Val->getType(); | ||
|
||
if (Trunc->hasNoUnsignedWrap()) { | ||
if (IsTrueDest) | ||
return ValueLatticeElement::get(ConstantInt::get(Ty, 1)); | ||
return ValueLatticeElement::get(Constant::getNullValue(Ty)); | ||
} | ||
|
||
if (IsTrueDest) | ||
return ValueLatticeElement::getNot(Constant::getNullValue(Ty)); | ||
return ValueLatticeElement::getNot(Constant::getAllOnesValue(Ty)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could further improve these by taking the nowrap flags into account. I think in a lot of cases we'll have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added handling for nuw and update the proof |
||
} | ||
|
||
// Handle conditions of the form | ||
// extractvalue(op.with.overflow(%x, C), 1). | ||
static ValueLatticeElement getValueFromOverflowCondition( | ||
|
@@ -1312,6 +1335,9 @@ LazyValueInfoImpl::getValueFromCondition(Value *Val, Value *Cond, | |
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond)) | ||
return getValueFromICmpCondition(Val, ICI, IsTrueDest, UseBlockValue); | ||
|
||
if (auto *Trunc = dyn_cast<TruncInst>(Cond)) | ||
return getValueFromTrunc(Val, Trunc, IsTrueDest); | ||
|
||
if (auto *EVI = dyn_cast<ExtractValueInst>(Cond)) | ||
if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand())) | ||
if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1515,10 +1515,8 @@ define void @test_trunc_bittest(i8 %a) { | |
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[A:%.*]] to i1 | ||
; CHECK-NEXT: br i1 [[TRUNC]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] | ||
; CHECK: if.true: | ||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP1]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP2]]) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
; CHECK-NEXT: call void @check1(i1 false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should also have negative tests, e.g. to show that it does not imply |
||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i8 [[A]], 1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP3]]) | ||
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[A]], 1 | ||
|
@@ -1559,10 +1557,8 @@ define void @test_trunc_not_bittest(i8 %a) { | |
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TRUNC]], true | ||
; CHECK-NEXT: br i1 [[NOT]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] | ||
; CHECK: if.true: | ||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[A]], -1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP1]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[A]], -1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP2]]) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
; CHECK-NEXT: call void @check1(i1 false) | ||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP3]]) | ||
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[A]], 0 | ||
|
@@ -1603,14 +1599,10 @@ define void @test_trunc_nuw_bittest(i8 %a) { | |
; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[A:%.*]] to i1 | ||
; CHECK-NEXT: br i1 [[TRUNC]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] | ||
; CHECK: if.true: | ||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP1]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP2]]) | ||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i8 [[A]], 1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP3]]) | ||
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[A]], 1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP4]]) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
dtcxzyw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
; CHECK-NEXT: call void @check1(i1 false) | ||
; CHECK-NEXT: call void @check1(i1 false) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
; CHECK-NEXT: ret void | ||
; CHECK: if.false: | ||
; CHECK-NEXT: ret void | ||
|
@@ -1639,14 +1631,10 @@ define void @test_trunc_nuw_not_bittest(i8 %a) { | |
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TRUNC]], true | ||
; CHECK-NEXT: br i1 [[NOT]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] | ||
; CHECK: if.true: | ||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP1]]) | ||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[A]], 0 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP2]]) | ||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i8 [[A]], 1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP3]]) | ||
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[A]], 1 | ||
; CHECK-NEXT: call void @check1(i1 [[CMP4]]) | ||
; CHECK-NEXT: call void @check1(i1 false) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
; CHECK-NEXT: call void @check1(i1 true) | ||
; CHECK-NEXT: call void @check1(i1 false) | ||
; CHECK-NEXT: ret void | ||
; CHECK: if.false: | ||
; CHECK-NEXT: ret void | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use
ConstantInt::getBool()
here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think it is not possible to use
ConstantInt::getBool()
as the type of val is not i1.it is possible to swap the true case to
ConstantInt::get(Ty, 1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I got confused with the types here. And yes, using ConstantInt::get is preferable. (getIntegerValue is a specialized API if you need to potentially create an inttoptr expression...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed