-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[ConstantRange] Estimate tighter lower (upper) bounds for masked binary and (or) #120352
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
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 |
---|---|---|
@@ -0,0 +1,88 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
; RUN: opt -S -passes=ipsccp %s | FileCheck %s | ||
|
||
declare void @use(i1) | ||
|
||
define i1 @test1(i64 %x) { | ||
; CHECK-LABEL: @test1( | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[COND:%.*]] = icmp ugt i64 [[X:%.*]], 65535 | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) | ||
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], -65521 | ||
; CHECK-NEXT: ret i1 false | ||
; | ||
entry: | ||
%cond = icmp ugt i64 %x, 65535 | ||
call void @llvm.assume(i1 %cond) | ||
%mask = and i64 %x, -65521 | ||
%cmp = icmp eq i64 %mask, 0 | ||
ret i1 %cmp | ||
} | ||
|
||
define void @test.and(i64 %x, i64 %y) { | ||
; CHECK-LABEL: @test.and( | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[C0:%.*]] = icmp uge i64 [[X:%.*]], 138 | ||
; CHECK-NEXT: [[C1:%.*]] = icmp ule i64 [[X]], 161 | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C0]]) | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C1]]) | ||
; CHECK-NEXT: [[C2:%.*]] = icmp uge i64 [[Y:%.*]], 186 | ||
; CHECK-NEXT: [[C3:%.*]] = icmp ule i64 [[Y]], 188 | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C2]]) | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C3]]) | ||
; CHECK-NEXT: [[AND:%.*]] = and i64 [[X]], [[Y]] | ||
; CHECK-NEXT: call void @use(i1 false) | ||
; CHECK-NEXT: [[R1:%.*]] = icmp ult i64 [[AND]], 137 | ||
; CHECK-NEXT: call void @use(i1 [[R1]]) | ||
; CHECK-NEXT: ret void | ||
; | ||
entry: | ||
%c0 = icmp uge i64 %x, 138 ; 0b10001010 | ||
%c1 = icmp ule i64 %x, 161 ; 0b10100000 | ||
call void @llvm.assume(i1 %c0) | ||
call void @llvm.assume(i1 %c1) | ||
%c2 = icmp uge i64 %y, 186 ; 0b10111010 | ||
%c3 = icmp ule i64 %y, 188 ; 0b10111110 | ||
call void @llvm.assume(i1 %c2) | ||
call void @llvm.assume(i1 %c3) | ||
%and = and i64 %x, %y | ||
%r0 = icmp ult i64 %and, 136 ; 0b10001000 | ||
call void @use(i1 %r0) ; false | ||
%r1 = icmp ult i64 %and, 137 | ||
call void @use(i1 %r1) ; unknown | ||
ret void | ||
} | ||
|
||
define void @test.or(i64 %x, i64 %y) { | ||
; CHECK-LABEL: @test.or( | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[C0:%.*]] = icmp ule i64 [[X:%.*]], 117 | ||
; CHECK-NEXT: [[C1:%.*]] = icmp uge i64 [[X]], 95 | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C0]]) | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C1]]) | ||
; CHECK-NEXT: [[C2:%.*]] = icmp ule i64 [[Y:%.*]], 69 | ||
; CHECK-NEXT: [[C3:%.*]] = icmp uge i64 [[Y]], 67 | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C2]]) | ||
; CHECK-NEXT: call void @llvm.assume(i1 [[C3]]) | ||
; CHECK-NEXT: [[OR:%.*]] = or i64 [[X]], [[Y]] | ||
; CHECK-NEXT: call void @use(i1 false) | ||
; CHECK-NEXT: [[R1:%.*]] = icmp ugt i64 [[OR]], 118 | ||
; CHECK-NEXT: call void @use(i1 [[R1]]) | ||
; CHECK-NEXT: ret void | ||
; | ||
entry: | ||
%c0 = icmp ule i64 %x, 117 ; 0b01110101 | ||
%c1 = icmp uge i64 %x, 95 ; 0b01011111 | ||
call void @llvm.assume(i1 %c0) | ||
call void @llvm.assume(i1 %c1) | ||
%c2 = icmp ule i64 %y, 69 ; 0b01000101 | ||
%c3 = icmp uge i64 %y, 67 ; 0b01000011 | ||
call void @llvm.assume(i1 %c2) | ||
call void @llvm.assume(i1 %c3) | ||
%or = or i64 %x, %y | ||
%r0 = icmp ugt i64 %or, 119 ; 0b01110111 | ||
call void @use(i1 %r0) ; false | ||
%r1 = icmp ugt i64 %or, 118 | ||
call void @use(i1 %r1) ; unknown | ||
ret void | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2720,6 +2720,37 @@ TEST_F(ConstantRangeTest, binaryAnd) { | |
EXPECT_EQ(R16_32.binaryAnd(R0_99), R0_32); | ||
EXPECT_EQ(R0_99.binaryAnd(R16_32), R0_32); | ||
|
||
// 'And' with leading bits are masked (with common leading bits stripped) | ||
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. What happens with signed ranges? [0b1..., 0b0...) Add a test? 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. 'And' op is tricky, since it operates regardless of the signedness and all ranges can be treated as unsigned. E.g., a range (with bitwidth=8) I'll add a test anyway. 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. Oh, if you're asking wrapped set, e.g., 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. Test added. |
||
ConstantRange RMaskedL(APInt(8, 0b10'00101'1), APInt(8, 0b10'10000'0 + 1)); | ||
ConstantRange RMaskedR(APInt(8, 0b10'11111'0), APInt(8, 0b10'11111'1 + 1)); | ||
EXPECT_EQ(RMaskedL.binaryAnd(RMaskedR).getLower(), APInt(8, 0b10'00101'0)); | ||
EXPECT_EQ(RMaskedR.binaryAnd(RMaskedL).getLower(), APInt(8, 0b10'00101'0)); | ||
|
||
ConstantRange RMaskedL1(APInt(8, 0b00'011'010), APInt(8, 0b00'100'100 + 1)); | ||
ConstantRange RMaskedR1(APInt(8, 0b00'111'010), APInt(8, 0b00'111'110 + 1)); | ||
EXPECT_EQ(RMaskedL1.binaryAnd(RMaskedR1).getLower(), APInt(8, 0b00'011'000)); | ||
EXPECT_EQ(RMaskedR1.binaryAnd(RMaskedL1).getLower(), APInt(8, 0b00'011'000)); | ||
|
||
ConstantRange RMaskedL2(APInt(8, 0b0000'0111u), APInt(8, 0b0000'1101u + 1u)); | ||
ConstantRange RMaskedR2(APInt(8, 0xff), APInt(8, 0)); | ||
EXPECT_EQ(RMaskedL2.binaryAnd(RMaskedR2), RMaskedL2); | ||
EXPECT_EQ(RMaskedR2.binaryAnd(RMaskedL2), RMaskedL2); | ||
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. can you add a test [3,15] [13,15] where the algorithm returns the non-optimal 1 (instead of 0)? 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. So, should I 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. |
||
|
||
ConstantRange RMaskedL3(APInt(4, 0b0011u), APInt(4, 0)); | ||
ConstantRange RMaskedR3(APInt(4, 0b1011u), APInt(4, 0)); | ||
APInt Zero_4(4, 0); | ||
EXPECT_EQ(RMaskedL3.binaryAnd(RMaskedR3).getLower().uge(Zero_4), true); | ||
EXPECT_EQ(RMaskedR3.binaryAnd(RMaskedL3).getLower().uge(Zero_4), true); | ||
|
||
// wrapped set | ||
APInt NegSeven(4, 9); // Also -7 | ||
ConstantRange RMaskedL4(NegSeven, APInt(4, 1)); | ||
ConstantRange RMaskedR4(NegSeven, APInt(4, 0)); | ||
EXPECT_EQ(RMaskedL4.binaryAnd(RMaskedR4).contains(Zero_4), true); | ||
EXPECT_EQ(RMaskedR4.binaryAnd(RMaskedL4).contains(Zero_4), true); | ||
EXPECT_EQ(RMaskedL4.binaryAnd(RMaskedR4).contains(NegSeven), true); | ||
EXPECT_EQ(RMaskedR4.binaryAnd(RMaskedL4).contains(NegSeven), true); | ||
|
||
TestBinaryOpExhaustive( | ||
[](const ConstantRange &CR1, const ConstantRange &CR2) { | ||
return CR1.binaryAnd(CR2); | ||
|
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 happened to analyze the problem in Oct and made a comment to
https://stackoverflow.com/questions/2620388/bitwise-interval-arithmetic
Do the two algorithms return the same result? If yes, my code seems simpler?
Uh oh!
There was an error while loading. Please reload this page.
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.
Aha, I saw your answer on SO before, but I don't think they are same. E.g., given
your algorithm gives the lower bound as
0b110000
, while mine gives0b110101
.And the original issue #118108 I try to fix is such a case.