summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2017-07-18 09:17:57 -0700
committerGitHub <noreply@github.com>2017-07-18 09:17:57 -0700
commite865f2fa2863b6e91521c059a61a4483769bf5c9 (patch)
treef2d4bbee701376a4975ebf0d2c518f10369fdabd
parent24accd15fb59d476daaebbbcd492b8a9ee729b2b (diff)
parent7bc2ed70de137aa6615fcd5d0e1f3e88f008a738 (diff)
downloadbinaryen-e865f2fa2863b6e91521c059a61a4483769bf5c9.tar.gz
binaryen-e865f2fa2863b6e91521c059a61a4483769bf5c9.tar.bz2
binaryen-e865f2fa2863b6e91521c059a61a4483769bf5c9.zip
Merge pull request #1095 from WebAssembly/fuzz-3
More fuzz fixes
-rw-r--r--src/asm2wasm.h7
-rw-r--r--src/ast/effects.h16
-rw-r--r--src/ast/properties.h24
-rw-r--r--src/passes/CoalesceLocals.cpp8
-rw-r--r--src/passes/MergeBlocks.cpp30
-rw-r--r--src/passes/OptimizeInstructions.cpp6
-rw-r--r--src/passes/Vacuum.cpp10
-rw-r--r--src/wasm-validator.h2
-rw-r--r--src/wasm/wasm-validator.cpp7
-rw-r--r--test/passes/coalesce-locals.txt41
-rw-r--r--test/passes/coalesce-locals.wast42
-rw-r--r--test/passes/optimize-instructions.txt31
-rw-r--r--test/passes/optimize-instructions.wast58
-rw-r--r--test/passes/remove-unused-brs_shrink-level=1.txt16
-rw-r--r--test/passes/remove-unused-brs_shrink-level=1.wast16
-rw-r--r--test/passes/remove-unused-names_merge-blocks.txt179
-rw-r--r--test/passes/remove-unused-names_merge-blocks.wast53
-rw-r--r--test/passes/remove-unused-names_vacuum.txt16
-rw-r--r--test/passes/remove-unused-names_vacuum.wast23
-rw-r--r--test/passes/vacuum.txt28
-rw-r--r--test/passes/vacuum.wast44
-rw-r--r--test/unit.asm.js7
-rw-r--r--test/unit.fromasm19
-rw-r--r--test/unit.fromasm.clamp19
-rw-r--r--test/unit.fromasm.clamp.no-opts19
-rw-r--r--test/unit.fromasm.imprecise19
-rw-r--r--test/unit.fromasm.imprecise.no-opts19
-rw-r--r--test/unit.fromasm.no-opts19
28 files changed, 695 insertions, 83 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 2245bd2b5..e2b1802b5 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -1397,7 +1397,12 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
void visitCallIndirect(CallIndirect* curr) {
// we already call into target = something + offset, where offset is a callImport with the name of the table. replace that with the table offset
// note that for an ftCall or mftCall, we have no asm.js mask, so have nothing to do here
- auto* add = curr->target->dynCast<Binary>();
+ auto* target = curr->target;
+ // might be a block with a fallthrough
+ if (auto* block = target->dynCast<Block>()) {
+ target = block->list.back();
+ }
+ auto* add = target->dynCast<Binary>();
if (!add) return;
if (add->right->is<CallImport>()) {
auto* offset = add->right->cast<CallImport>();
diff --git a/src/ast/effects.h b/src/ast/effects.h
index a7a5d8fb2..6e4bb617e 100644
--- a/src/ast/effects.h
+++ b/src/ast/effects.h
@@ -39,7 +39,7 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer> {
if (breakNames.size() > 0) branches = true;
}
- bool branches = false; // branches out of this expression
+ bool branches = false; // branches out of this expression, returns, infinite loops, etc
bool calls = false;
std::set<Index> localsRead;
std::set<Index> localsWritten;
@@ -138,6 +138,18 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer> {
}
void visitLoop(Loop* curr) {
if (curr->name.is()) breakNames.erase(curr->name); // these were internal breaks
+ // if the loop is unreachable, then there is branching control flow:
+ // (1) if the body is unreachable because of a (return), uncaught (br) etc., then we
+ // already noted branching, so it is ok to mark it again (if we have *caught*
+ // (br)s, then they did not lead to the loop body being unreachable).
+ // (same logic applies to blocks)
+ // (2) if the loop is unreachable because it only has branches up to the loop
+ // top, but no way to get out, then it is an infinite loop, and we consider
+ // that a branching side effect (note how the same logic does not apply to
+ // blocks).
+ if (curr->type == unreachable) {
+ branches = true;
+ }
}
void visitCall(Call *curr) { calls = true; }
@@ -182,6 +194,7 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer> {
case TruncUFloat64ToInt32:
case TruncUFloat64ToInt64: {
implicitTrap = true;
+ break;
}
default: {}
}
@@ -199,6 +212,7 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer> {
case RemSInt64:
case RemUInt64: {
implicitTrap = true;
+ break;
}
default: {}
}
diff --git a/src/ast/properties.h b/src/ast/properties.h
index 9121deba5..097f7a8f0 100644
--- a/src/ast/properties.h
+++ b/src/ast/properties.h
@@ -60,11 +60,13 @@ struct Properties {
if (auto* outer = curr->dynCast<Binary>()) {
if (outer->op == ShrSInt32) {
if (auto* outerConst = outer->right->dynCast<Const>()) {
- if (auto* inner = outer->left->dynCast<Binary>()) {
- if (inner->op == ShlInt32) {
- if (auto* innerConst = inner->right->dynCast<Const>()) {
- if (outerConst->value == innerConst->value) {
- return inner->left;
+ if (outerConst->value.geti32() != 0) {
+ if (auto* inner = outer->left->dynCast<Binary>()) {
+ if (inner->op == ShlInt32) {
+ if (auto* innerConst = inner->right->dynCast<Const>()) {
+ if (outerConst->value == innerConst->value) {
+ return inner->left;
+ }
}
}
}
@@ -87,11 +89,13 @@ struct Properties {
if (auto* outer = curr->dynCast<Binary>()) {
if (outer->op == ShrSInt32) {
if (auto* outerConst = outer->right->dynCast<Const>()) {
- 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()) {
- return inner->left;
+ if (outerConst->value.geti32() != 0) {
+ 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()) {
+ return inner->left;
+ }
}
}
}
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index b36542a97..5ab68da23 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -196,7 +196,9 @@ struct CoalesceLocals : public WalkerPass<CFGWalker<CoalesceLocals, Visitor<Coal
if (auto* get = set->value->dynCast<GetLocal>()) return get;
if (auto* iff = set->value->dynCast<If>()) {
if (auto* get = iff->ifTrue->dynCast<GetLocal>()) return get;
- if (auto* get = iff->ifFalse->dynCast<GetLocal>()) return get;
+ if (iff->ifFalse) {
+ if (auto* get = iff->ifFalse->dynCast<GetLocal>()) return get;
+ }
}
return nullptr;
}
@@ -595,11 +597,13 @@ void CoalesceLocals::pickIndices(std::vector<Index>& indices) {
// Remove a copy from a set of an if, where one if arm is a get of the same set
static void removeIfCopy(Expression** origin, SetLocal* set, If* iff, Expression*& copy, Expression*& other, Module* module) {
// replace the origin with the if, and sink the set into the other non-copying arm
+ bool tee = set->isTee();
*origin = iff;
set->value = other;
set->finalize();
other = set;
- if (!isConcreteWasmType(set->type)) {
+ // if this is not a tee, then we can get rid of the copy in that arm
+ if (!tee) {
// we don't need the copy at all
copy = nullptr;
if (!iff->ifTrue) {
diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp
index 2c983d991..bc5fea6fb 100644
--- a/src/passes/MergeBlocks.cpp
+++ b/src/passes/MergeBlocks.cpp
@@ -188,6 +188,15 @@ static void optimizeBlock(Block* curr, Module* module) {
}
if (!child) continue;
if (child->name.is()) continue; // named blocks can have breaks to them (and certainly do, if we ran RemoveUnusedNames and RemoveUnusedBrs)
+ if (child->type == unreachable) {
+ // an unreachable block can have a concrete final element (which is never reached)
+ if (!child->list.empty()) {
+ if (isConcreteWasmType(child->list.back()->type)) {
+ // just remove it
+ child->list.pop_back();
+ }
+ }
+ }
ExpressionList merged(module->allocator);
for (size_t j = 0; j < i; j++) {
merged.push_back(curr->list[j]);
@@ -279,11 +288,14 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
}
void visitSelect(Select* curr) {
+ // TODO: for now, just stop when we see any side effect. instead, we could
+ // check effects carefully for reordering
Block* outer = nullptr;
- outer = optimize(curr, curr->ifTrue, outer);
if (EffectAnalyzer(getPassOptions(), curr->ifTrue).hasSideEffects()) return;
- outer = optimize(curr, curr->ifFalse, outer);
+ outer = optimize(curr, curr->ifTrue, outer);
if (EffectAnalyzer(getPassOptions(), curr->ifFalse).hasSideEffects()) return;
+ outer = optimize(curr, curr->ifFalse, outer);
+ if (EffectAnalyzer(getPassOptions(), curr->condition).hasSideEffects()) return;
optimize(curr, curr->condition, outer);
}
@@ -299,11 +311,13 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
}
template<typename T>
- void handleCall(T* curr, Block* outer = nullptr) {
+ void handleCall(T* curr) {
+ Block* outer = nullptr;
for (Index i = 0; i < curr->operands.size(); i++) {
- outer = optimize(curr, curr->operands[i], outer);
if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects()) return;
+ outer = optimize(curr, curr->operands[i], outer);
}
+ return;
}
void visitCall(Call* curr) {
@@ -315,9 +329,13 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
}
void visitCallIndirect(CallIndirect* curr) {
- auto* outer = optimize(curr, curr->target);
+ Block* outer = nullptr;
+ for (Index i = 0; i < curr->operands.size(); i++) {
+ if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects()) return;
+ outer = optimize(curr, curr->operands[i], outer);
+ }
if (EffectAnalyzer(getPassOptions(), curr->target).hasSideEffects()) return;
- handleCall(curr, outer);
+ optimize(curr, curr->target, outer);
}
};
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index d1b419a06..c6006d712 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -517,6 +517,12 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
}
+ // some operations have no effect TODO: many more
+ if (right->value == Literal(int32_t(0))) {
+ if (binary->op == ShlInt32 || binary->op == ShrUInt32 || binary->op == ShrSInt32) {
+ return binary->left;
+ }
+ }
// the square of some operations can be merged
if (auto* left = binary->left->dynCast<Binary>()) {
if (left->op == binary->op) {
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index 40f4a6e59..3f27fb36a 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -232,6 +232,16 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum>> {
replaceCurrent(child);
return;
}
+ // if the condition is unreachable, just return it
+ if (curr->condition->type == unreachable) {
+ typeUpdater.noteRecursiveRemoval(curr->ifTrue);
+ if (curr->ifFalse) {
+ typeUpdater.noteRecursiveRemoval(curr->ifFalse);
+ }
+ replaceCurrent(curr->condition);
+ return;
+ }
+ // from here on, we can assume the condition executed
if (curr->ifFalse) {
if (curr->ifFalse->is<Nop>()) {
curr->ifFalse = nullptr;
diff --git a/src/wasm-validator.h b/src/wasm-validator.h
index f778e6f24..a359102ea 100644
--- a/src/wasm-validator.h
+++ b/src/wasm-validator.h
@@ -220,7 +220,7 @@ public:
void shouldBeIntOrUnreachable(WasmType ty, Expression* curr, const char* text);
void validateAlignment(size_t align, WasmType type, Index bytes, bool isAtomic,
Expression* curr);
- void validateMemBytes(uint8_t bytes, WasmType ty, Expression* curr);
+ void validateMemBytes(uint8_t bytes, WasmType type, Expression* curr);
void validateBinaryenIR(Module& wasm);
};
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 1b328ec19..5ca6b2783 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -261,14 +261,17 @@ void WasmValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
shouldBeEqualOrFirstIsUnreachable(curr->replacement->type, curr->type, curr, "Cmpxchg result type must match replacement");
shouldBeIntOrUnreachable(curr->expected->type, curr, "Atomic operations are only valid on int types");
}
-void WasmValidator::validateMemBytes(uint8_t bytes, WasmType ty, Expression* curr) {
+void WasmValidator::validateMemBytes(uint8_t bytes, WasmType type, Expression* curr) {
+ if (type == unreachable) {
+ return; // nothing to validate in this case
+ }
switch (bytes) {
case 1:
case 2:
case 4:
break;
case 8: {
- shouldBeEqual(getWasmTypeSize(ty), 8U, curr, "8-byte mem operations are only allowed with 8-byte wasm types");
+ shouldBeEqual(getWasmTypeSize(type), 8U, curr, "8-byte mem operations are only allowed with 8-byte wasm types");
break;
}
default: fail("Memory operations must be 1,2,4, or 8 bytes", curr);
diff --git a/test/passes/coalesce-locals.txt b/test/passes/coalesce-locals.txt
index f8dc3ef0f..32da026ac 100644
--- a/test/passes/coalesce-locals.txt
+++ b/test/passes/coalesce-locals.txt
@@ -7,6 +7,7 @@
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$vi (func (param i32)))
(type $7 (func (param i32) (result i32)))
+ (type $8 (func (param f64 i32) (result i64)))
(import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32)))
(import "env" "get" (func $get (result i32)))
(import "env" "set" (func $set (param i32)))
@@ -1112,4 +1113,44 @@
)
(i32.const 1)
)
+ (func $unused-tee-with-child-if-no-else (type $4) (param $0 i32)
+ (loop $label$0
+ (drop
+ (if
+ (br $label$0)
+ (nop)
+ )
+ )
+ )
+ )
+ (func $tee_if_with_unreachable_else (type $8) (param $0 f64) (param $1 i32) (result i64)
+ (call $tee_if_with_unreachable_else
+ (if (result f64)
+ (get_local $1)
+ (get_local $0)
+ (tee_local $0
+ (unreachable)
+ )
+ )
+ (f64.lt
+ (f64.const -128)
+ (get_local $0)
+ )
+ )
+ )
+ (func $tee_if_with_unreachable_true (type $8) (param $0 f64) (param $1 i32) (result i64)
+ (call $tee_if_with_unreachable_else
+ (if (result f64)
+ (get_local $1)
+ (tee_local $0
+ (unreachable)
+ )
+ (get_local $0)
+ )
+ (f64.lt
+ (f64.const -128)
+ (get_local $0)
+ )
+ )
+ )
)
diff --git a/test/passes/coalesce-locals.wast b/test/passes/coalesce-locals.wast
index 336c75e0e..ee92bb05e 100644
--- a/test/passes/coalesce-locals.wast
+++ b/test/passes/coalesce-locals.wast
@@ -1085,4 +1085,46 @@
)
(i32.const 1)
)
+ (func $unused-tee-with-child-if-no-else (param $0 i32)
+ (loop $label$0
+ (drop
+ (tee_local $0
+ (if
+ (br $label$0)
+ (nop)
+ )
+ )
+ )
+ )
+ )
+ (func $tee_if_with_unreachable_else (param $0 f64) (param $1 i32) (result i64)
+ (call $tee_if_with_unreachable_else
+ (tee_local $0
+ (if (result f64)
+ (get_local $1)
+ (get_local $0)
+ (unreachable)
+ )
+ )
+ (f64.lt
+ (f64.const -128)
+ (get_local $0)
+ )
+ )
+ )
+ (func $tee_if_with_unreachable_true (param $0 f64) (param $1 i32) (result i64)
+ (call $tee_if_with_unreachable_else
+ (tee_local $0
+ (if (result f64)
+ (get_local $1)
+ (unreachable)
+ (get_local $0)
+ )
+ )
+ (f64.lt
+ (f64.const -128)
+ (get_local $0)
+ )
+ )
+ )
)
diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt
index c8fe17cf0..8b42fd2ad 100644
--- a/test/passes/optimize-instructions.txt
+++ b/test/passes/optimize-instructions.txt
@@ -1962,4 +1962,35 @@
)
)
)
+ (func $zero-shifts-is-not-sign-ext (type $1)
+ (drop
+ (i32.eq
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const -5431187)
+ )
+ )
+ (drop
+ (i32.eq
+ (i32.shl
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const 1)
+ )
+ (i32.const -5431187)
+ )
+ )
+ )
+ (func $zero-ops (type $2) (result i32)
+ (return
+ (i32.eq
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const -1337)
+ )
+ )
+ )
)
diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast
index bb89d7314..6d1fd60ed 100644
--- a/test/passes/optimize-instructions.wast
+++ b/test/passes/optimize-instructions.wast
@@ -2359,4 +2359,62 @@
)
)
)
+ (func $zero-shifts-is-not-sign-ext
+ (drop
+ (i32.eq
+ (i32.const -5431187)
+ (i32.add
+ (i32.const 0)
+ (i32.shr_s
+ (i32.shl
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ )
+ )
+ (drop
+ (i32.eq
+ (i32.const -5431187)
+ (i32.add
+ (i32.const 0)
+ (i32.shr_s
+ (i32.shl
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0)
+ )
+ )
+ )
+ )
+ )
+ (func $zero-ops (result i32)
+ (return
+ (i32.eq
+ (i32.const -1337)
+ (i32.shr_u
+ (i32.add
+ (i32.const 0)
+ (i32.shr_s
+ (i32.shl
+ (i32.load16_s align=1
+ (i32.const 790656516)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/remove-unused-brs_shrink-level=1.txt b/test/passes/remove-unused-brs_shrink-level=1.txt
index 09e727ea5..a26f4ebf4 100644
--- a/test/passes/remove-unused-brs_shrink-level=1.txt
+++ b/test/passes/remove-unused-brs_shrink-level=1.txt
@@ -123,4 +123,20 @@
)
)
)
+ (func $join-and-it-becomes-unreachable (type $1)
+ (block $label$1
+ (block $block
+ (br_if $label$1
+ (i32.load8_u
+ (i32.const -93487262)
+ )
+ )
+ (br_if $label$1
+ (loop $label$5
+ (br $label$5)
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/remove-unused-brs_shrink-level=1.wast b/test/passes/remove-unused-brs_shrink-level=1.wast
index 000658b91..88977be9e 100644
--- a/test/passes/remove-unused-brs_shrink-level=1.wast
+++ b/test/passes/remove-unused-brs_shrink-level=1.wast
@@ -77,5 +77,21 @@
(br_if $out8 (call $b14)) ;; side effect
)
)
+ (func $join-and-it-becomes-unreachable
+ (block $label$1
+ (block
+ (br_if $label$1
+ (i32.load8_u
+ (i32.const -93487262)
+ )
+ )
+ (br_if $label$1
+ (loop $label$5 ;; this is unreachable (infinite loop, no exit)
+ (br $label$5)
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/remove-unused-names_merge-blocks.txt b/test/passes/remove-unused-names_merge-blocks.txt
index ed448607d..bc42f2766 100644
--- a/test/passes/remove-unused-names_merge-blocks.txt
+++ b/test/passes/remove-unused-names_merge-blocks.txt
@@ -4,6 +4,7 @@
(type $iii (func (param i32 i32 i32)))
(type $3 (func))
(type $4 (func (result i32)))
+ (type $5 (func (result f64)))
(table 1 1 anyfunc)
(elem (i32.const 0) $call-i)
(memory $0 256 256)
@@ -411,26 +412,34 @@
)
)
)
- (unreachable)
- (drop
- (i32.const 30)
- )
- (drop
- (i32.const 50)
- )
(drop
(select
- (i32.const 20)
- (i32.const 40)
- (i32.const 60)
+ (block (result i32)
+ (unreachable)
+ (i32.const 20)
+ )
+ (block (result i32)
+ (drop
+ (i32.const 30)
+ )
+ (i32.const 40)
+ )
+ (block (result i32)
+ (drop
+ (i32.const 50)
+ )
+ (i32.const 60)
+ )
)
)
(drop
- (i32.const 10)
- )
- (drop
(select
- (unreachable)
+ (block (result i32)
+ (drop
+ (i32.const 10)
+ )
+ (unreachable)
+ )
(block (result i32)
(drop
(i32.const 30)
@@ -448,27 +457,33 @@
(drop
(i32.const 10)
)
- (unreachable)
- (drop
- (i32.const 50)
- )
(drop
(select
(i32.const 20)
- (i32.const 40)
- (i32.const 60)
+ (block
+ (unreachable)
+ (i32.const 40)
+ )
+ (block (result i32)
+ (drop
+ (i32.const 50)
+ )
+ (i32.const 60)
+ )
)
)
(drop
(i32.const 10)
)
(drop
- (i32.const 30)
- )
- (drop
(select
(i32.const 20)
- (unreachable)
+ (block
+ (drop
+ (i32.const 30)
+ )
+ (unreachable)
+ )
(block (result i32)
(drop
(i32.const 50)
@@ -483,12 +498,14 @@
(drop
(i32.const 30)
)
- (unreachable)
(drop
(select
(i32.const 20)
(i32.const 40)
- (i32.const 60)
+ (block
+ (unreachable)
+ (i32.const 60)
+ )
)
)
(drop
@@ -498,13 +515,15 @@
(i32.const 30)
)
(drop
- (i32.const 50)
- )
- (drop
(select
(i32.const 20)
(i32.const 40)
- (unreachable)
+ (block
+ (drop
+ (i32.const 50)
+ )
+ (unreachable)
+ )
)
)
)
@@ -589,19 +608,25 @@
(i32.const 20)
(i32.const 40)
)
- (unreachable)
- (drop
- (i32.const 20)
- )
(call $call-ii
- (i32.const 10)
- (i32.const 30)
- )
- (drop
- (i32.const 10)
+ (block (result i32)
+ (unreachable)
+ (i32.const 10)
+ )
+ (block (result i32)
+ (drop
+ (i32.const 20)
+ )
+ (i32.const 30)
+ )
)
(call $call-ii
- (unreachable)
+ (block (result i32)
+ (drop
+ (i32.const 10)
+ )
+ (unreachable)
+ )
(block (result i32)
(drop
(i32.const 20)
@@ -612,20 +637,24 @@
(drop
(i32.const 10)
)
- (unreachable)
(call $call-ii
(i32.const 20)
- (i32.const 30)
+ (block
+ (unreachable)
+ (i32.const 30)
+ )
)
(drop
(i32.const 10)
)
- (drop
- (i32.const 30)
- )
(call $call-ii
(i32.const 20)
- (unreachable)
+ (block
+ (drop
+ (i32.const 30)
+ )
+ (unreachable)
+ )
)
(drop
(i32.const 10)
@@ -653,22 +682,19 @@
(i32.const 50)
)
(drop
- (i32.const 50)
- )
- (drop
(i32.const 10)
)
(drop
(i32.const 30)
)
+ (drop
+ (i32.const 50)
+ )
(call_indirect $ii
(i32.const 20)
(i32.const 40)
(i32.const 60)
)
- (drop
- (i32.const 50)
- )
(call_indirect $ii
(unreachable)
(block (result i32)
@@ -677,7 +703,50 @@
)
(i32.const 40)
)
- (i32.const 60)
+ (block (result i32)
+ (drop
+ (i32.const 50)
+ )
+ (i32.const 60)
+ )
+ )
+ (drop
+ (i32.const 31)
+ )
+ (call_indirect $ii
+ (i32.const 41)
+ (unreachable)
+ (block (result i32)
+ (drop
+ (i32.const 51)
+ )
+ (i32.const 61)
+ )
+ )
+ (drop
+ (i32.const 32)
+ )
+ (drop
+ (i32.const 52)
+ )
+ (call_indirect $ii
+ (i32.const 42)
+ (i32.const 62)
+ (unreachable)
+ )
+ )
+ (func $mix-select (type $i) (param $x i32)
+ (drop
+ (select
+ (get_local $x)
+ (get_local $x)
+ (block (result i32)
+ (set_local $x
+ (i32.const 1)
+ )
+ (i32.const 2)
+ )
+ )
)
)
(func $block-type-change (type $3)
@@ -748,4 +817,8 @@
)
(unreachable)
)
+ (func $concrete_finale_in_unreachable (type $5) (result f64)
+ (unreachable)
+ (f64.const -1)
+ )
)
diff --git a/test/passes/remove-unused-names_merge-blocks.wast b/test/passes/remove-unused-names_merge-blocks.wast
index 5cefa357e..346dc78f8 100644
--- a/test/passes/remove-unused-names_merge-blocks.wast
+++ b/test/passes/remove-unused-names_merge-blocks.wast
@@ -854,6 +854,50 @@
(i32.const 60)
)
)
+ (call_indirect $ii
+ (block $block21 (result i32)
+ (drop
+ (i32.const 31)
+ )
+ (i32.const 41)
+ )
+ (unreachable)
+ (block $block22 (result i32)
+ (drop
+ (i32.const 51)
+ )
+ (i32.const 61)
+ )
+ )
+ (call_indirect $ii
+ (block $block21 (result i32)
+ (drop
+ (i32.const 32)
+ )
+ (i32.const 42)
+ )
+ (block $block22 (result i32)
+ (drop
+ (i32.const 52)
+ )
+ (i32.const 62)
+ )
+ (unreachable)
+ )
+ )
+ (func $mix-select (param $x i32)
+ (drop
+ (select
+ (get_local $x)
+ (get_local $x)
+ (block (result i32)
+ (set_local $x ;; cannot be moved before the gets
+ (i32.const 1)
+ )
+ (i32.const 2)
+ )
+ )
+ )
)
(func $block-type-change (type $3)
(local $0 f64)
@@ -926,4 +970,13 @@
(unreachable)
)
)
+ (func $concrete_finale_in_unreachable (result f64)
+ (block $label$0 (result f64)
+ (block ;; this block is unreachable
+ (unreachable)
+ (f64.const 6.322092475576799e-96)
+ )
+ (f64.const -1)
+ )
+ )
)
diff --git a/test/passes/remove-unused-names_vacuum.txt b/test/passes/remove-unused-names_vacuum.txt
index 999d8915e..d27fb3d65 100644
--- a/test/passes/remove-unused-names_vacuum.txt
+++ b/test/passes/remove-unused-names_vacuum.txt
@@ -4,11 +4,15 @@
(memory $0 0)
(func $return-i32-but-body-is-unreachable3 (type $0) (result i32)
(local $label i32)
- (unreachable)
+ (loop $while-in$1
+ (br $while-in$1)
+ )
)
(func $return-i32-but-body-is-unreachable4 (type $0) (result i32)
(local $label i32)
- (unreachable)
+ (loop $while-in$1
+ (br $while-in$1)
+ )
)
(func $to-drop-unreachable (type $1)
(drop
@@ -17,4 +21,12 @@
)
)
)
+ (func $return-i32-but-body-is-unreachable5 (type $0) (result i32)
+ (local $label i32)
+ (unreachable)
+ )
+ (func $return-i32-but-body-is-unreachable6 (type $0) (result i32)
+ (local $label i32)
+ (unreachable)
+ )
)
diff --git a/test/passes/remove-unused-names_vacuum.wast b/test/passes/remove-unused-names_vacuum.wast
index f45f50274..66412353c 100644
--- a/test/passes/remove-unused-names_vacuum.wast
+++ b/test/passes/remove-unused-names_vacuum.wast
@@ -16,12 +16,25 @@
)
(i32.const 0)
)
- (func $to-drop-unreachable
- (drop
- (block (result i32)
- (unreachable)
+ (func $to-drop-unreachable
+ (drop
+ (block (result i32)
+ (unreachable)
+ )
)
)
- )
+ (func $return-i32-but-body-is-unreachable5 (result i32)
+ (local $label i32)
+ (block ;; without a name here, vaccum had a too-eager bug
+ (unreachable)
+ )
+ )
+ (func $return-i32-but-body-is-unreachable6 (result i32)
+ (local $label i32)
+ (block ;; without a name here, vaccum had a too-eager bug
+ (unreachable)
+ )
+ (i32.const 0)
+ )
)
diff --git a/test/passes/vacuum.txt b/test/passes/vacuum.txt
index e07357296..f3b06af1a 100644
--- a/test/passes/vacuum.txt
+++ b/test/passes/vacuum.txt
@@ -273,4 +273,32 @@
)
)
)
+ (func $unreachable-if-with-nop-arm-that-leaves-a-concrete-value-if-nop-is-removed (type $0)
+ (block $label$0
+ (loop $label$1
+ (br_if $label$0
+ (i32.load8_s
+ (i32.const 1634541608)
+ )
+ (loop $label$9
+ (br $label$9)
+ )
+ )
+ )
+ )
+ )
+ (func $if-arm-vanishes (type $3) (result i32)
+ (block $label$0 (result i32)
+ (br $label$0
+ (i32.const 1)
+ )
+ )
+ )
+ (func $if-arm-vanishes-2 (type $3) (result i32)
+ (block $label$0 (result i32)
+ (br $label$0
+ (i32.const 1)
+ )
+ )
+ )
)
diff --git a/test/passes/vacuum.wast b/test/passes/vacuum.wast
index 77ffabd60..db4bf6749 100644
--- a/test/passes/vacuum.wast
+++ b/test/passes/vacuum.wast
@@ -593,4 +593,48 @@
)
)
)
+ (func $unreachable-if-with-nop-arm-that-leaves-a-concrete-value-if-nop-is-removed
+ (block $label$0
+ (loop $label$1
+ (if
+ (br_if $label$0
+ (i32.load8_s
+ (i32.const 1634541608)
+ )
+ (loop $label$9
+ (br $label$9)
+ )
+ )
+ (nop)
+ (i32.const 1920103026)
+ )
+ )
+ )
+ )
+ (func $if-arm-vanishes (result i32)
+ (block $label$0 (result i32)
+ (block $label$1
+ (if
+ (br $label$0
+ (i32.const 1)
+ )
+ (br $label$1)
+ )
+ )
+ (i32.const 1579493952)
+ )
+ )
+ (func $if-arm-vanishes-2 (result i32)
+ (block $label$0 (result i32)
+ (block $label$1
+ (if
+ (br $label$0
+ (i32.const 1)
+ )
+ (br $label$1)
+ )
+ )
+ (i32.const 1579493952)
+ )
+ )
)
diff --git a/test/unit.asm.js b/test/unit.asm.js
index 0bd0ab21b..22e180078 100644
--- a/test/unit.asm.js
+++ b/test/unit.asm.js
@@ -709,12 +709,19 @@ function asm(global, env, buffer) {
i1 = (FUNCTION_TABLE_vi[1 & 7](0), 1);
}
+ function emterpretify_assertions_safeHeap() {
+ var i1 = 0;
+ // assignment into the function table param, optimizer can do things there
+ FUNCTION_TABLE_vi[(Int = 1) & 7](i1 | 0);
+ }
+
function keepAlive() {
sqrts(3.14159);
f2u(100.0);
f2s(100.0);
autoDrop(52) | 0;
indirectInSequence();
+ emterpretify_assertions_safeHeap();
}
function v() {
diff --git a/test/unit.fromasm b/test/unit.fromasm
index c869e2398..68f5920ee 100644
--- a/test/unit.fromasm
+++ b/test/unit.fromasm
@@ -1169,6 +1169,24 @@
(i32.const 17)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $0 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $0)
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (i32.add
+ (i32.and
+ (get_global $Int)
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1191,6 +1209,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $vi (param $0 i32)
(nop)
diff --git a/test/unit.fromasm.clamp b/test/unit.fromasm.clamp
index 370e66c4d..1442ea947 100644
--- a/test/unit.fromasm.clamp
+++ b/test/unit.fromasm.clamp
@@ -1193,6 +1193,24 @@
(i32.const 17)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $0 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $0)
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (i32.add
+ (i32.and
+ (get_global $Int)
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1215,6 +1233,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $vi (param $0 i32)
(nop)
diff --git a/test/unit.fromasm.clamp.no-opts b/test/unit.fromasm.clamp.no-opts
index 8ff26568e..37456128f 100644
--- a/test/unit.fromasm.clamp.no-opts
+++ b/test/unit.fromasm.clamp.no-opts
@@ -1977,6 +1977,24 @@
)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $i1 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $i1)
+ (i32.add
+ (i32.and
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (get_global $Int)
+ )
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1999,6 +2017,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $v
(nop)
diff --git a/test/unit.fromasm.imprecise b/test/unit.fromasm.imprecise
index 45912cffb..ea664d5f0 100644
--- a/test/unit.fromasm.imprecise
+++ b/test/unit.fromasm.imprecise
@@ -1142,6 +1142,24 @@
(i32.const 17)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $0 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $0)
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (i32.add
+ (i32.and
+ (get_global $Int)
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1164,6 +1182,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $vi (param $0 i32)
(nop)
diff --git a/test/unit.fromasm.imprecise.no-opts b/test/unit.fromasm.imprecise.no-opts
index 3747f2c90..227cf5e79 100644
--- a/test/unit.fromasm.imprecise.no-opts
+++ b/test/unit.fromasm.imprecise.no-opts
@@ -1937,6 +1937,24 @@
)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $i1 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $i1)
+ (i32.add
+ (i32.and
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (get_global $Int)
+ )
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1959,6 +1977,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $v
(nop)
diff --git a/test/unit.fromasm.no-opts b/test/unit.fromasm.no-opts
index dba91cfcd..878011cef 100644
--- a/test/unit.fromasm.no-opts
+++ b/test/unit.fromasm.no-opts
@@ -1953,6 +1953,24 @@
)
)
)
+ (func $emterpretify_assertions_safeHeap
+ (local $i1 i32)
+ (call_indirect $FUNCSIG$vi
+ (get_local $i1)
+ (i32.add
+ (i32.and
+ (block (result i32)
+ (set_global $Int
+ (i32.const 1)
+ )
+ (get_global $Int)
+ )
+ (i32.const 7)
+ )
+ (i32.const 16)
+ )
+ )
+ )
(func $keepAlive
(drop
(call $sqrts
@@ -1975,6 +1993,7 @@
)
)
(call $indirectInSequence)
+ (call $emterpretify_assertions_safeHeap)
)
(func $v
(nop)