Skip to content
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

Implement more cases for getMaxBits #2879

Merged
merged 88 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
ee08839
implement 64-bit cases for getMaxBits
MaxGraey May 27, 2020
374c9b6
add ExtendSInt32 & ExtendUInt32 for unary cases
MaxGraey May 27, 2020
3a0f72e
fix ExtendSInt32
MaxGraey May 27, 2020
091e15e
implement RemUInt32 / RemUInt64 for getMaxBits
MaxGraey May 27, 2020
18a2aa2
implement DivUInt(32/64) / DivSInt(32/64)
MaxGraey May 27, 2020
168fed4
Implement RemSInt32 / RemSInt64
MaxGraey May 27, 2020
d04ae7d
update according review
MaxGraey May 27, 2020
c08376c
Merge branch 'master' into more-getmaxbits
MaxGraey May 30, 2020
2dc792c
fix missing returns for rest cases
MaxGraey May 30, 2020
56146d3
Merge branch 'master' into more-getmaxbits
MaxGraey Jun 2, 2020
3f68768
Merge branch 'master' into more-getmaxbits
MaxGraey Jun 2, 2020
36f73e5
rearrange cases
MaxGraey Jun 2, 2020
c77d5d4
calc getMaxBits also for multiply
MaxGraey Jun 5, 2020
d60b53e
Merge branch 'master' into more-getmaxbits
MaxGraey Jun 5, 2020
0bba5b6
lint
MaxGraey Jun 5, 2020
f43c8db
generalize div / rem for all type dividers
MaxGraey Jun 5, 2020
a6415e1
add fast paths when divider or multiplier is zero
MaxGraey Jun 5, 2020
d979620
more optimizations
MaxGraey Jun 5, 2020
6685e6d
lint
MaxGraey Jun 5, 2020
7726f18
revert generalizations for div / rem
MaxGraey Jun 5, 2020
a39091a
return max bits of left expr for udiv as default case
MaxGraey Jun 5, 2020
908eb96
Merge branch 'master' into more-getmaxbits
MaxGraey Jun 5, 2020
df767f4
return zero when lhs also zero for mul
MaxGraey Jun 6, 2020
73ad57d
Merge branch 'master' into more-getmaxbits
MaxGraey Jul 22, 2020
6b8d232
wip
MaxGraey Jul 22, 2020
f387148
fix using geti32 instead geti64 for 64-bit consts
MaxGraey Jul 22, 2020
38ee4e7
cleanups
MaxGraey Jul 22, 2020
74f10d5
Merge branch 'master' into more-getmaxbits
MaxGraey Jul 24, 2020
fa13337
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 4, 2020
2e9ab76
resolve conflicts
MaxGraey Aug 4, 2020
3ea4530
cleanups
MaxGraey Aug 4, 2020
252ce01
more fixes after resolving conflicts
MaxGraey Aug 4, 2020
fd4e8cf
more fancy unit test error output
MaxGraey Aug 4, 2020
60b7b55
lint
MaxGraey Aug 4, 2020
d93f65d
fixture refresh
MaxGraey Aug 4, 2020
c9fe2cb
add basic tests
MaxGraey Aug 4, 2020
14ae90c
print line and file for assertion errors
MaxGraey Aug 4, 2020
90f39d4
more
MaxGraey Aug 4, 2020
5a99214
refactor
MaxGraey Aug 4, 2020
64aded9
-> failCount
MaxGraey Aug 4, 2020
4b2061a
-> failsCount
MaxGraey Aug 5, 2020
216b6fa
simplify output to cout as well
MaxGraey Aug 5, 2020
c631b94
add basic tests fo divs
MaxGraey Aug 5, 2020
d0a4938
finish div tests
MaxGraey Aug 5, 2020
543d239
more
MaxGraey Aug 5, 2020
5673101
more
MaxGraey Aug 5, 2020
ae827a8
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 5, 2020
8567487
reduce to two consts
MaxGraey Aug 5, 2020
957e945
reorder color consts
MaxGraey Aug 5, 2020
d5d6d2b
use Bits ns
MaxGraey Aug 5, 2020
709b8ed
add rem_s / rem_u tests
MaxGraey Aug 5, 2020
569362f
add and / or / xor tests
MaxGraey Aug 5, 2020
9545f9e
add unary ops
MaxGraey Aug 5, 2020
9085d8e
remove check to zero for rhs consts
MaxGraey Aug 7, 2020
422e46f
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 11, 2020
551a675
changes according review
MaxGraey Aug 11, 2020
d7335a8
also ahndling sub32/sub64
MaxGraey Aug 12, 2020
3a27ca3
linter
MaxGraey Aug 12, 2020
e0739c3
add early returns for negative or zero lhs
MaxGraey Aug 12, 2020
74e568c
remove redundant upper bound limit
MaxGraey Aug 12, 2020
ae75346
Merge remote-tracking branch 'WebAssembly/master' into more-getmaxbits
MaxGraey Aug 13, 2020
6883ce7
cleanup tests
MaxGraey Aug 13, 2020
0cc2e85
remove naeg checks for MulInt32/MulInt64
MaxGraey Aug 14, 2020
acd6518
simplify SubInt32/SubInt64
MaxGraey Aug 14, 2020
df40a08
more tests
MaxGraey Aug 14, 2020
da177ae
add antiexample
MaxGraey Aug 16, 2020
d84f9ba
larger value (255 -> 1023)
MaxGraey Aug 16, 2020
5c1d1c4
add example with global
MaxGraey Aug 16, 2020
f319270
make blobal exportable
MaxGraey Aug 16, 2020
55d9824
more tests
MaxGraey Aug 16, 2020
f924008
revert getMaxBits for subtractions + remove fixtures
MaxGraey Aug 16, 2020
790a05c
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 18, 2020
30b1842
remove some zero checks
MaxGraey Aug 18, 2020
341a3ef
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 22, 2020
b91ee8c
add comments + refactorings
MaxGraey Aug 22, 2020
719d8c3
Merge branch 'master' into more-getmaxbits
MaxGraey Aug 27, 2020
146c966
refactor DivSInt32|64 / DivUInt32|64
MaxGraey Aug 28, 2020
a74f10e
more tests and fixes
MaxGraey Aug 28, 2020
b4d614d
refactor
MaxGraey Aug 28, 2020
9b2fe4d
lint
MaxGraey Aug 28, 2020
162c94d
more tests
MaxGraey Aug 28, 2020
8404d91
indent
MaxGraey Aug 28, 2020
4be0956
simplify
MaxGraey Aug 28, 2020
ec62420
Merge branch 'master' into more-getmaxbits
MaxGraey Sep 16, 2020
5fc687a
Update src/ir/bits.h
MaxGraey Sep 16, 2020
0be9076
Update src/ir/bits.h
MaxGraey Sep 16, 2020
33c9eab
add CeilLog2 util
MaxGraey Sep 16, 2020
277d159
lint
MaxGraey Sep 16, 2020
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
203 changes: 186 additions & 17 deletions src/ir/bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,35 +128,92 @@ struct DummyLocalInfoProvider {
template<typename LocalInfoProvider = DummyLocalInfoProvider>
Index getMaxBits(Expression* curr,
LocalInfoProvider* localInfoProvider = nullptr) {
if (auto* const_ = curr->dynCast<Const>()) {
if (auto* c = curr->dynCast<Const>()) {
switch (curr->type.getBasic()) {
case Type::i32:
return 32 - const_->value.countLeadingZeroes().geti32();
return 32 - c->value.countLeadingZeroes().geti32();
case Type::i64:
return 64 - const_->value.countLeadingZeroes().geti64();
return 64 - c->value.countLeadingZeroes().geti64();
default:
WASM_UNREACHABLE("invalid type");
}
} else if (auto* binary = curr->dynCast<Binary>()) {
switch (binary->op) {
// 32-bit
case AddInt32:
case SubInt32:
case MulInt32:
case DivSInt32:
case DivUInt32:
case RemSInt32:
case RemUInt32:
case RotLInt32:
case RotRInt32:
case SubInt32:
return 32;
case AddInt32: {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
return std::min(Index(32), std::max(maxBitsLeft, maxBitsRight) + 1);
}
case MulInt32: {
auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
return std::min(Index(32), maxBitsLeft + maxBitsRight);
}
case DivSInt32: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 32) {
return 32;
}
MaxGraey marked this conversation as resolved.
Show resolved Hide resolved
if (maxBitsLeft == 0) {
return 0;
}
Copy link
Member

Choose a reason for hiding this comment

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

I thought we agreed that there should not be such checks for 0 (because 0 should be handled elsewhere already)? Please remove them all.

Copy link
Contributor Author

@MaxGraey MaxGraey Aug 18, 2020

Choose a reason for hiding this comment

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

If I remove that check:

b.op = DivSInt32;
c0.value = Literal(int32_t(0));
c1.value = Literal(int32_t(0xF));
auto t = getMaxBits(&b)

t without early check return 4294967293 or -1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it ok?

auto value = c->value.geti32();
auto maxBitsRight = 31 - Index(CountLeadingZeroes(value));
Copy link
Member

@kripken kripken Aug 18, 2020

Choose a reason for hiding this comment

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

Does this almost duplicate code from line 144? Why is it duplicated, and why is it different?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, could you made link to this line? line 144 contain something non-similar to that code.

Copy link
Member

Choose a reason for hiding this comment

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

It's the line that computes the max bits for a Const,

  if (auto* const_ = curr->dynCast<Const>()) {
    switch (curr->type.getBasic()) {
      case Type::i32:
        return 32 - const_->value.countLeadingZeroes().geti32();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see. So you suggest change it to:

auto maxBitsRight = 31 - c->value.countLeadingZeroes().geti32();

or

auto maxBitsRight = getMaxBits(c, localInfoProvider) - 1;

?

Copy link
Member

Choose a reason for hiding this comment

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

Why -1? It's weird to see

foo = getFoo() - 1

foo on both sides, but with a difference, is odd.

I think the meaning is different than max bits, but I'm not sure what it is? Is it the topmost bit maybe? Or one past that?

But given the below comment, and this is just for consts, you probably don't want localInfoProvider there - it doesn't help.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it should be maxLeftBits - rightBits + 1. It's easily check on next example:
maxBits(0x7FFFFFFF / 3) == 30

maxLeftBits = maxBits(0x7FFFFFFF) is 31
rightBits = maxBits(3) is 2

31 - 2 ==> 29
31 - 2 + 1 ==> 30

also it properly handle case when maxLeftBits == rightBits

return std::max(Index(0), maxBitsLeft - maxBitsRight);
Copy link
Member

Choose a reason for hiding this comment

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

The type here looks wrong. the maxBits are both unsigned, so the difference is unsigned too. So if it would be negative, it will be a very big positive number, and "win" in the max operation.

Aside from the type it also looks wrong. We know that

left <= 2^maxBitsLeft
right <= 2^maxBitsRight

(from the definition of maxBits). but that doesn't imply

left / right <= 2^(maxBitsLeft - maxBitsRight)

The only inequality I can almost see how to prove is

left / right <= 2^maxBitsLeft

but even that isn't quite right, as right may be 0, even if maxBitsRight > 0. This is similar to the issue from before: maxBits is an upper bound.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm. Perhaps it's not so simple. Decide check how do this in souper and it's look more complex

Copy link
Contributor Author

@MaxGraey MaxGraey Aug 20, 2020

Choose a reason for hiding this comment

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

So it seems there uses

if (getMaxBits(right) != 32)
  return min(32, 31 + getMinBits(left) - getMaxBits(right))
else
  return getMinBits(left);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but even that isn't quite right, as right may be 0, even if maxBitsRight > 0. This is similar to the issue from before: maxBits is an upper bound.

It's easily could be rejected due to current implementation do max bits div calcs only for x / C(onst): https://github.com/WebAssembly/binaryen/pull/2879/files#diff-58b7cf13906e9b5a4ba6306aaea394aaR158. Right value always const in my scenario. I don't try calc bits for general case like x / y

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see. Yes, if the right value is a const, then this is simpler. In that case, the variable name maxBitsRight is confusing - it's not the max bits, it's the actual number of bits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I refactored and now using bitsRight instead maxBitsRight

}
return 32;
}
case DivUInt32: {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 0) {
return 0;
}
if (auto* c = binary->right->dynCast<Const>()) {
auto value = c->value.geti32();
auto maxBitsRight = 31 - Index(CountLeadingZeroes(value));
return std::max(Index(0), maxBitsLeft - maxBitsRight);
}
return maxBitsLeft;
}
case RemSInt32: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 32) {
return 32;
}
auto value = c->value.geti32();
auto maxBitsRight = 32 - Index(CountLeadingZeroes(value - 1));
return std::min(maxBitsLeft, maxBitsRight);
}
return 32;
case AndInt32:
return std::min(getMaxBits(binary->left, localInfoProvider),
getMaxBits(binary->right, localInfoProvider));
}
case RemUInt32: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
auto value = c->value.geti32();
auto maxBitsRight = 32 - Index(CountLeadingZeroes(value - 1));
return std::min(maxBitsLeft, maxBitsRight);
}
return 32;
}
case AndInt32: {
auto maxBits = getMaxBits(binary->right, localInfoProvider);
return std::min(getMaxBits(binary->left, localInfoProvider), maxBits);
MaxGraey marked this conversation as resolved.
Show resolved Hide resolved
}
case OrInt32:
case XorInt32:
return std::max(getMaxBits(binary->left, localInfoProvider),
getMaxBits(binary->right, localInfoProvider));
case XorInt32: {
auto maxBits = getMaxBits(binary->right, localInfoProvider);
Copy link
Member

Choose a reason for hiding this comment

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

Is there reason to believe that checking the right side first will save more work than checking the left side first, or is it an arbitrary choice?

Copy link
Contributor Author

@MaxGraey MaxGraey Sep 16, 2020

Choose a reason for hiding this comment

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

Yes, right side could be cheaper due to canonization which always force constant on the right. Also x ^ -1 is quite often case.

if (maxBits == 32) {
return 32;
}
return std::max(getMaxBits(binary->left, localInfoProvider), maxBits);
}
case ShlInt32: {
if (auto* shifts = binary->right->dynCast<Const>()) {
return std::min(Index(32),
Expand Down Expand Up @@ -188,7 +245,111 @@ Index getMaxBits(Expression* curr,
}
return 32;
}
// 64-bit TODO
case RotLInt64:
case RotRInt64:
case SubInt64:
return 64;
case AddInt64: {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
return std::min(Index(64), std::max(maxBitsLeft, maxBitsRight) + 1);
MaxGraey marked this conversation as resolved.
Show resolved Hide resolved
}
case MulInt64: {
auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
return std::min(Index(64), maxBitsLeft + maxBitsRight);
}
case DivSInt64: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 64) {
return 64;
}
if (maxBitsLeft == 0) {
return 0;
}
auto value = c->value.geti64();
auto maxBitsRight = 63 - Index(CountLeadingZeroes(value));
return std::max(Index(0), maxBitsLeft - maxBitsRight);
}
return 64;
}
case DivUInt64: {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 0) {
return 0;
}
if (auto* c = binary->right->dynCast<Const>()) {
auto value = c->value.geti64();
auto maxBitsRight = 63 - Index(CountLeadingZeroes(value));
return std::max(Index(0), maxBitsLeft - maxBitsRight);
}
return maxBitsLeft;
}
case RemSInt64: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
if (maxBitsLeft == 64) {
return 64;
}
auto value = c->value.geti64();
auto maxBitsRight = 64 - Index(CountLeadingZeroes(value - 1));
return std::min(maxBitsLeft, maxBitsRight);
}
return 64;
}
case RemUInt64: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
auto value = c->value.geti64();
auto maxBitsRight = 64 - Index(CountLeadingZeroes(value - 1));
return std::min(maxBitsLeft, maxBitsRight);
}
return 64;
}
case AndInt64: {
auto maxBits = getMaxBits(binary->right, localInfoProvider);
return std::min(getMaxBits(binary->left, localInfoProvider), maxBits);
}
case OrInt64:
case XorInt64: {
auto maxBits = getMaxBits(binary->right, localInfoProvider);
if (maxBits == 64) {
return 64;
}
return std::max(getMaxBits(binary->left, localInfoProvider), maxBits);
}
case ShlInt64: {
if (auto* shifts = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
return std::min(Index(64),
Bits::getEffectiveShifts(shifts) + maxBits);
}
return 64;
}
case ShrUInt64: {
if (auto* shift = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
auto shifts =
std::min(Index(Bits::getEffectiveShifts(shift)),
maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 64;
}
case ShrSInt64: {
if (auto* shift = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
if (maxBits == 64) {
return 64;
}
auto shifts =
std::min(Index(Bits::getEffectiveShifts(shift)),
maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 64;
}
// comparisons
case EqInt32:
case NeInt32:
Expand All @@ -200,6 +361,7 @@ Index getMaxBits(Expression* curr,
case GtUInt32:
case GeSInt32:
case GeUInt32:

case EqInt64:
case NeInt64:
case LtSInt64:
Expand All @@ -210,12 +372,14 @@ Index getMaxBits(Expression* curr,
case GtUInt64:
case GeSInt64:
case GeUInt64:

case EqFloat32:
case NeFloat32:
case LtFloat32:
case LeFloat32:
case GtFloat32:
case GeFloat32:

case EqFloat64:
case NeFloat64:
case LtFloat64:
Expand All @@ -240,7 +404,12 @@ Index getMaxBits(Expression* curr,
case EqZInt64:
return 1;
case WrapInt64:
case ExtendUInt32:
return std::min(Index(32), getMaxBits(unary->value, localInfoProvider));
case ExtendSInt32: {
auto maxBits = getMaxBits(unary->value, localInfoProvider);
return maxBits == 32 ? Index(64) : maxBits;
}
default: {
}
}
Expand Down
Loading