diff options
-rw-r--r-- | src/ast/bits.h | 3 | ||||
-rw-r--r-- | src/ast/properties.h | 8 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 8 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 10 | ||||
-rw-r--r-- | test/passes/optimize-instructions.txt | 77 | ||||
-rw-r--r-- | test/passes/optimize-instructions.wast | 70 | ||||
-rw-r--r-- | test/polymorphic_stack.wast | 10 | ||||
-rw-r--r-- | test/polymorphic_stack.wast.from-wast | 10 | ||||
-rw-r--r-- | test/polymorphic_stack.wast.fromBinary | 11 | ||||
-rw-r--r-- | test/polymorphic_stack.wast.fromBinary.noDebugInfo | 11 |
10 files changed, 199 insertions, 19 deletions
diff --git a/src/ast/bits.h b/src/ast/bits.h index 11cf7b06d..0aee50ffe 100644 --- a/src/ast/bits.h +++ b/src/ast/bits.h @@ -51,7 +51,8 @@ struct Bits { WASM_UNREACHABLE(); } - static Index getEffectiveShifts(Const* amount) { + static Index getEffectiveShifts(Expression* expr) { + auto* amount = expr->cast<Const>(); if (amount->type == i32) { return getEffectiveShifts(amount->value.geti32(), i32); } else if (amount->type == i64) { diff --git a/src/ast/properties.h b/src/ast/properties.h index 097f7a8f0..8c8655c07 100644 --- a/src/ast/properties.h +++ b/src/ast/properties.h @@ -79,7 +79,7 @@ struct Properties { // gets the size of the sign-extended value static Index getSignExtBits(Expression* curr) { - return 32 - curr->cast<Binary>()->right->cast<Const>()->value.geti32(); + return 32 - Bits::getEffectiveShifts(curr->cast<Binary>()->right); } // Check if an expression is almost a sign-extend: perhaps the inner shift @@ -93,7 +93,7 @@ struct Properties { if (auto* inner = outer->left->dynCast<Binary>()) { if (inner->op == ShlInt32) { if (auto* innerConst = inner->right->dynCast<Const>()) { - if (outerConst->value.leU(innerConst->value).geti32()) { + if (Bits::getEffectiveShifts(outerConst) <= Bits::getEffectiveShifts(innerConst)) { return inner->left; } } @@ -109,8 +109,8 @@ struct Properties { // gets the size of the almost sign-extended value, as well as the // extra shifts, if any static Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) { - extraShifts = curr->cast<Binary>()->left->cast<Binary>()->right->cast<Const>()->value.geti32() - - curr->cast<Binary>()->right->cast<Const>()->value.geti32(); + extraShifts = Bits::getEffectiveShifts(curr->cast<Binary>()->left->cast<Binary>()->right) - + Bits::getEffectiveShifts(curr->cast<Binary>()->right); return getSignExtBits(curr); } diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 4fd7cbe8d..f458a58b2 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -228,8 +228,8 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) { } } else if (auto* unary = curr->dynCast<Unary>()) { switch (unary->op) { - case ClzInt32: case CtzInt32: case PopcntInt32: return 5; - case ClzInt64: case CtzInt64: case PopcntInt64: return 6; + case ClzInt32: case CtzInt32: case PopcntInt32: return 6; + case ClzInt64: case CtzInt64: case PopcntInt64: return 7; case EqZInt32: case EqZInt64: return 1; case WrapInt64: return std::min(Index(32), getMaxBits(unary->value, localInfoProvider)); default: {} @@ -779,7 +779,7 @@ private: return; } else if (binary->op == ShlInt32) { if (auto* c = binary->right->dynCast<Const>()) { - seek(binary->left, mul * Pow2(c->value.geti32())); + seek(binary->left, mul * Pow2(Bits::getEffectiveShifts(c))); return; } } else if (binary->op == MulInt32) { @@ -836,7 +836,7 @@ private: } } else if (curr->op == ShlInt32) { // shifting a 0 is a 0, unless the shift has side effects - if (left && left->value.geti32() == 0 && !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) { + if (left && Bits::getEffectiveShifts(left) == 0 && !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) { replaceCurrent(left); return; } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 88b967fdf..47bcc8ba5 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -666,6 +666,14 @@ void WasmBinaryWriter::visitSwitch(Switch *curr) { recurse(curr->value); } recurse(curr->condition); + if (!BranchUtils::isBranchTaken(curr)) { + // if the branch is not taken, then it's dangerous to emit it, as + // wasm type checking rules are stricter than ours - we tolerate + // an untaken branch to a target with a different value, but not + // wasm. so just don't emit it + o << int8_t(BinaryConsts::Unreachable); + return; + } o << int8_t(BinaryConsts::TableSwitch) << U32LEB(curr->targets.size()); for (auto target : curr->targets) { o << U32LEB(getBreakIndex(target)); @@ -1796,7 +1804,7 @@ void WasmBinaryBuilder::processExpressions() { // until an end or else marker, o Expression* WasmBinaryBuilder::popExpression() { if (expressionStack.empty()) { - throw ParseException("attempted pop from empty stack"); + throw ParseException("attempted pop from empty stack at " + std::to_string(pos)); } auto ret = expressionStack.back(); // to simulate the wasm polymorphic stack mode, leave a final diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt index a399a9096..55501dfb8 100644 --- a/test/passes/optimize-instructions.txt +++ b/test/passes/optimize-instructions.txt @@ -7,6 +7,7 @@ (type $5 (func (param i32))) (type $6 (func (param i32 i32) (result i32))) (type $7 (func (param i64) (result i64))) + (type $8 (func (result i64))) (memory $0 0) (export "load-off-2" (func $load-off-2)) (func $f (type $0) (param $i1 i32) (param $i2 i64) @@ -827,11 +828,14 @@ ) ) (drop - (i32.shl - (i32.clz - (i32.const 0) + (i32.shr_s + (i32.shl + (i32.clz + (i32.const 0) + ) + (i32.const 26) ) - (i32.const 2) + (i32.const 24) ) ) (drop @@ -853,13 +857,16 @@ ) ) (drop - (i32.shl - (i32.wrap/i64 - (i64.clz - (i64.const 0) + (i32.shr_s + (i32.shl + (i32.wrap/i64 + (i64.clz + (i64.const 0) + ) ) + (i32.const 25) ) - (i32.const 1) + (i32.const 24) ) ) (drop @@ -2061,4 +2068,56 @@ (i32.const 9) ) ) + (func $mix-shifts (type $2) (result i32) + (i32.shr_s + (i32.shl + (i32.const 23) + (i32.const -61) + ) + (i32.const 168) + ) + ) + (func $actually-no-shifts (type $2) (result i32) + (i32.const 33) + ) + (func $less-shifts-than-it-seems (type $3) (param $x i32) (result i32) + (i32.const 4800) + ) + (func $and-popcount32 (type $2) (result i32) + (i32.and + (i32.popcnt + (i32.const -1) + ) + (i32.const 31) + ) + ) + (func $and-popcount32-big (type $2) (result i32) + (i32.popcnt + (i32.const -1) + ) + ) + (func $and-popcount64 (type $8) (result i64) + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 63) + ) + ) + (func $and-popcount64-big (type $8) (result i64) + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 127) + ) + ) + (func $and-popcount64-bigger (type $8) (result i64) + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 255) + ) + ) ) diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast index 8362453e9..c26aad196 100644 --- a/test/passes/optimize-instructions.wast +++ b/test/passes/optimize-instructions.wast @@ -2496,4 +2496,74 @@ (i32.const 4098) ;; 2 bits effectively ) ) + (func $mix-shifts (result i32) + (i32.shr_s + (i32.shl + (i32.const 23) + (i32.const -61) + ) + (i32.const 168) + ) + ) + (func $actually-no-shifts (result i32) + (i32.add + (i32.shl + (i32.const 23) + (i32.const 32) ;; really 0 + ) + (i32.const 10) + ) + ) + (func $less-shifts-than-it-seems (param $x i32) (result i32) + (i32.add + (i32.shl + (i32.const 200) + (i32.const 36) ;; really 4 + ) + (i32.shl + (i32.const 100) + (i32.const 4) + ) + ) + ) + (func $and-popcount32 (result i32) + (i32.and + (i32.popcnt + (i32.const -1) + ) + (i32.const 31) + ) + ) + (func $and-popcount32-big (result i32) + (i32.and + (i32.popcnt + (i32.const -1) + ) + (i32.const 63) + ) + ) + (func $and-popcount64 (result i64) ;; these are TODOs + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 63) + ) + ) + (func $and-popcount64-big (result i64) + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 127) + ) + ) + (func $and-popcount64-bigger (result i64) + (i64.and + (i64.popcnt + (i64.const -1) + ) + (i64.const 255) + ) + ) ) diff --git a/test/polymorphic_stack.wast b/test/polymorphic_stack.wast index 2241ab910..b618fbb6c 100644 --- a/test/polymorphic_stack.wast +++ b/test/polymorphic_stack.wast @@ -86,5 +86,15 @@ ) ) ) + (func $br_table_unreachable_to_also_unreachable (result i32) + (block $a (result i32) + (block $b + (br_table $a $b ;; seems to send a value, but is not taken + (unreachable) + (unreachable) + ) + ) + ) + ) ) diff --git a/test/polymorphic_stack.wast.from-wast b/test/polymorphic_stack.wast.from-wast index b4b88f16b..c20f9218d 100644 --- a/test/polymorphic_stack.wast.from-wast +++ b/test/polymorphic_stack.wast.from-wast @@ -90,4 +90,14 @@ ) ) ) + (func $br_table_unreachable_to_also_unreachable (type $1) (result i32) + (block $a (result i32) + (block $b + (br_table $a $b + (unreachable) + (unreachable) + ) + ) + ) + ) ) diff --git a/test/polymorphic_stack.wast.fromBinary b/test/polymorphic_stack.wast.fromBinary index e0ee6577d..b139c9c06 100644 --- a/test/polymorphic_stack.wast.fromBinary +++ b/test/polymorphic_stack.wast.fromBinary @@ -125,5 +125,16 @@ (unreachable) ) ) + (func $br_table_unreachable_to_also_unreachable (type $1) (result i32) + (block $label$0 (result i32) + (block $label$1 + (unreachable) + (unreachable) + (unreachable) + (unreachable) + ) + (unreachable) + ) + ) ) diff --git a/test/polymorphic_stack.wast.fromBinary.noDebugInfo b/test/polymorphic_stack.wast.fromBinary.noDebugInfo index 857a3660c..e707d5046 100644 --- a/test/polymorphic_stack.wast.fromBinary.noDebugInfo +++ b/test/polymorphic_stack.wast.fromBinary.noDebugInfo @@ -125,5 +125,16 @@ (unreachable) ) ) + (func $6 (type $1) (result i32) + (block $label$0 (result i32) + (block $label$1 + (unreachable) + (unreachable) + (unreachable) + (unreachable) + ) + (unreachable) + ) + ) ) |