summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/literal.h85
-rw-r--r--src/passes/OptimizeInstructions.cpp23
2 files changed, 97 insertions, 11 deletions
diff --git a/src/literal.h b/src/literal.h
index eedccabcc..33300c920 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -96,7 +96,57 @@ public:
}
return false;
}
+ bool isZero() const {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return i32 == 0;
+ case Type::i64:
+ return i64 == 0LL;
+ case Type::f32:
+ return bit_cast<float>(i32) == 0.0f;
+ case Type::f64:
+ return bit_cast<double>(i64) == 0.0;
+ case Type::v128: {
+ uint8_t zeros[16] = {0};
+ return memcmp(&v128, zeros, 16) == 0;
+ }
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ bool isSignedMin() const {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return i32 == std::numeric_limits<int32_t>::min();
+ case Type::i64:
+ return i64 == std::numeric_limits<int64_t>::min();
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ bool isSignedMax() const {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return i32 == std::numeric_limits<int32_t>::max();
+ case Type::i64:
+ return i64 == std::numeric_limits<int64_t>::max();
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ bool isUnsignedMax() const {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return uint32_t(i32) == std::numeric_limits<uint32_t>::max();
+ case Type::i64:
+ return uint64_t(i64) == std::numeric_limits<uint64_t>::max();
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ static Literals makeZero(Type type);
+ static Literal makeSingleZero(Type type);
static Literal makeFromInt32(int32_t x, Type type) {
switch (type.getBasic()) {
case Type::i32:
@@ -116,7 +166,6 @@ public:
WASM_UNREACHABLE("unexpected type");
}
}
-
static Literal makeFromUInt64(uint64_t x, Type type) {
switch (type.getBasic()) {
case Type::i32:
@@ -131,10 +180,36 @@ public:
WASM_UNREACHABLE("unexpected type");
}
}
-
- static Literals makeZero(Type type);
- static Literal makeSingleZero(Type type);
-
+ static Literal makeSignedMin(Type type) {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return Literal(std::numeric_limits<int32_t>::min());
+ case Type::i64:
+ return Literal(std::numeric_limits<int64_t>::min());
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ static Literal makeSignedMax(Type type) {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return Literal(std::numeric_limits<int32_t>::max());
+ case Type::i64:
+ return Literal(std::numeric_limits<int64_t>::max());
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ static Literal makeUnsignedMax(Type type) {
+ switch (type.getBasic()) {
+ case Type::i32:
+ return Literal(std::numeric_limits<uint32_t>::max());
+ case Type::i64:
+ return Literal(std::numeric_limits<uint64_t>::max());
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
static Literal makeNull(Type type) {
assert(type.isNullable());
return Literal(type);
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 79315ac6d..de96e418e 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -298,15 +298,16 @@ struct OptimizeInstructions
}
}
{
- // eqz((signed)x % C_pot) => eqz(x & (C_pot - 1))
+ // eqz((signed)x % C_pot) => eqz(x & (abs(C_pot) - 1))
Const* c;
Binary* inner;
if (matches(curr,
unary(Abstract::EqZ,
binary(&inner, Abstract::RemS, any(), ival(&c)))) &&
- Bits::isPowerOf2((uint64_t)c->value.getInteger())) {
+ !c->value.isSignedMin() &&
+ Bits::isPowerOf2(c->value.abs().getInteger())) {
inner->op = Abstract::getBinary(c->type, Abstract::And);
- c->value = c->value.sub(Literal::makeFromInt32(1, c->type));
+ c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type));
return curr;
}
}
@@ -1307,7 +1308,16 @@ private:
right->value = Literal::makeSingleZero(type);
return right;
}
- // (signed)x % C_pot != 0 ==> x & (C_pot - 1) != 0
+ {
+ // (signed)x % (i32|i64).min_s ==> (x & (i32|i64).max_s)
+ if (matches(curr, binary(Abstract::RemS, any(&left), ival())) &&
+ right->value.isSignedMin()) {
+ curr->op = Abstract::getBinary(type, Abstract::And);
+ right->value = Literal::makeSignedMax(type);
+ return curr;
+ }
+ }
+ // (signed)x % C_pot != 0 ==> (x & (abs(C_pot) - 1)) != 0
{
Const* c;
Binary* inner;
@@ -1315,9 +1325,10 @@ private:
binary(Abstract::Ne,
binary(&inner, Abstract::RemS, any(), ival(&c)),
ival(0))) &&
- Bits::isPowerOf2((uint64_t)c->value.getInteger())) {
+ !c->value.isSignedMin() &&
+ Bits::isPowerOf2(c->value.abs().getInteger())) {
inner->op = Abstract::getBinary(c->type, Abstract::And);
- c->value = c->value.sub(Literal::makeFromInt32(1, c->type));
+ c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type));
return curr;
}
}