summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xauto_update_tests.py7
-rwxr-xr-xcheck.py7
-rwxr-xr-xscripts/test/support.py5
-rw-r--r--src/asm2wasm.h1
-rw-r--r--src/wasm-builder.h6
-rw-r--r--src/wasm.h14
-rw-r--r--src/wasm/wasm-binary.cpp11
-rw-r--r--src/wasm/wasm-s-parser.cpp7
-rw-r--r--src/wasm/wasm.cpp61
-rw-r--r--test/passes/O.bin.txt117
-rw-r--r--test/passes/O.wasmbin0 -> 330 bytes
-rw-r--r--test/passes/dce.txt51
-rw-r--r--test/passes/dce_vacuum.bin.txt101
-rw-r--r--test/passes/dce_vacuum.txt19
-rw-r--r--test/passes/dce_vacuum.wasmbin0 -> 260 bytes
-rw-r--r--test/passes/dce_vacuum.wast37
16 files changed, 403 insertions, 41 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py
index 0c07001e2..d76d08750 100755
--- a/auto_update_tests.py
+++ b/auto_update_tests.py
@@ -84,9 +84,10 @@ for t in sorted(os.listdir(os.path.join('test', 'print'))):
with open(os.path.join('test', 'print', wasm + '.minified.txt'), 'w') as o: o.write(actual)
for t in sorted(os.listdir(os.path.join('test', 'passes'))):
- if t.endswith('.wast'):
+ if t.endswith(('.wast', '.wasm')):
print '..', t
- passname = os.path.basename(t).replace('.wast', '')
+ binary = '.wasm' in t
+ passname = os.path.basename(t).replace('.wast', '').replace('.wasm', '')
opts = ['-' + passname] if passname.startswith('O') else ['--' + p for p in passname.split('_')]
t = os.path.join('test', 'passes', t)
actual = ''
@@ -95,7 +96,7 @@ for t in sorted(os.listdir(os.path.join('test', 'passes'))):
with open('split.wast', 'w') as o: o.write(module)
cmd = WASM_OPT + opts + ['split.wast', '--print']
actual += run_command(cmd)
- with open(os.path.join('test', 'passes', passname + '.txt'), 'w') as o: o.write(actual)
+ with open(os.path.join('test', 'passes', passname + ('.bin' if binary else '') + '.txt'), 'w') as o: o.write(actual)
print '\n[ checking wasm-opt -o notation... ]\n'
diff --git a/check.py b/check.py
index 3989c1a2c..ca5d74efd 100755
--- a/check.py
+++ b/check.py
@@ -74,9 +74,10 @@ assert open('b.wast', 'rb').read()[0] != '\0', 'we emit text with -S'
print '\n[ checking wasm-opt passes... ]\n'
for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'passes'))):
- if t.endswith('.wast'):
+ if t.endswith(('.wast', '.wasm')):
print '..', t
- passname = os.path.basename(t).replace('.wast', '')
+ binary = '.wasm' in t
+ passname = os.path.basename(t).replace('.wast', '').replace('.wasm', '')
opts = ['-' + passname] if passname.startswith('O') else ['--' + p for p in passname.split('_')]
t = os.path.join(options.binaryen_test, 'passes', t)
actual = ''
@@ -88,7 +89,7 @@ for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'passes'))):
# also check debug mode output is valid
debugged = run_command(cmd + ['--debug'], stderr=subprocess.PIPE)
fail_if_not_contained(actual, debugged)
- fail_if_not_identical(actual, open(os.path.join(options.binaryen_test, 'passes', passname + '.txt'), 'rb').read())
+ fail_if_not_identical(actual, open(os.path.join('test', 'passes', passname + ('.bin' if binary else '') + '.txt'), 'rb').read())
print '[ checking asm2wasm testcases... ]\n'
diff --git a/scripts/test/support.py b/scripts/test/support.py
index 43762fffa..5d791d155 100755
--- a/scripts/test/support.py
+++ b/scripts/test/support.py
@@ -94,6 +94,11 @@ def split_wast(wast):
# this splits out a wast into [(module, assertions), ..]
# we ignore module invalidity tests here.
wast = open(wast).read()
+
+ # if it's a binary, leave it as is
+ if wast[0] == '\0':
+ return [[wast, '']]
+
ret = []
def to_end(j):
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 00481c9bd..2fbe4d0ae 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -2296,6 +2296,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
Break *continuer = allocator.alloc<Break>();
continuer->name = in;
continuer->condition = process(ast[1]);
+ continuer->finalize();
Block *block = builder.blockifyWithName(loop->body, out, continuer);
loop->body = block;
loop->finalize();
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 6b3f1a7d7..61db3c9e8 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -288,7 +288,7 @@ public:
if (!block) block = makeBlock(any);
if (append) {
block->list.push_back(append);
- block->finalize(); // TODO: move out of if
+ block->finalize();
}
return block;
}
@@ -302,7 +302,7 @@ public:
block->name = name;
if (append) {
block->list.push_back(append);
- block->finalize(); // TODO: move out of if
+ block->finalize();
}
return block;
}
@@ -325,7 +325,7 @@ public:
block->list.push_back(item);
}
}
- block->finalize(); // TODO: move out of if
+ block->finalize();
return block;
}
diff --git a/src/wasm.h b/src/wasm.h
index b23dab918..3caab9dbc 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -309,6 +309,8 @@ public:
ExpressionList operands;
Name target;
+
+ void finalize();
};
class CallImport : public SpecificExpression<Expression::CallImportId> {
@@ -317,6 +319,8 @@ public:
ExpressionList operands;
Name target;
+
+ void finalize();
};
class FunctionType {
@@ -340,6 +344,8 @@ public:
ExpressionList operands;
Name fullType;
Expression* target;
+
+ void finalize();
};
class GetLocal : public SpecificExpression<Expression::GetLocalId> {
@@ -355,6 +361,8 @@ public:
SetLocal() {}
SetLocal(MixedArena& allocator) {}
+ void finalize();
+
Index index;
Expression* value;
@@ -377,6 +385,8 @@ public:
Name name;
Expression* value;
+
+ void finalize();
};
class Load : public SpecificExpression<Expression::LoadId> {
@@ -391,6 +401,8 @@ public:
Expression* ptr;
// type must be set during creation, cannot be inferred
+
+ void finalize();
};
class Store : public SpecificExpression<Expression::StoreId> {
@@ -466,6 +478,8 @@ public:
Drop(MixedArena& allocator) {}
Expression* value;
+
+ void finalize();
};
class Return : public SpecificExpression<Expression::ReturnId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 159099a16..6448615a5 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -676,7 +676,8 @@ void WasmBinaryWriter::visitLoad(Load *curr) {
}
case f32: o << int8_t(BinaryConsts::F32LoadMem); break;
case f64: o << int8_t(BinaryConsts::F64LoadMem); break;
- default: abort();
+ case unreachable: return; // the pointer is unreachable, so we are never reached; just don't emit a load
+ default: WASM_UNREACHABLE();
}
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
}
@@ -1732,7 +1733,6 @@ Expression* WasmBinaryBuilder::getBlock(WasmType type) {
Name label = getNextLabel();
breakStack.push_back({label, type != none && type != unreachable});
auto* block = Builder(wasm).blockify(getMaybeBlock(type));
- block->finalize();
breakStack.pop_back();
block->cast<Block>()->name = label;
return block;
@@ -1814,6 +1814,7 @@ Expression* WasmBinaryBuilder::visitCall() {
call->target = import->name;
type = wasm.getFunctionType(import->functionType);
fillCall(call, type);
+ call->finalize();
ret = call;
} else {
// this is a call of a defined function
@@ -1825,6 +1826,7 @@ Expression* WasmBinaryBuilder::visitCall() {
type = functionTypes[adjustedIndex];
fillCall(call, type);
functionCalls[adjustedIndex].push_back(call); // we don't know function names yet
+ call->finalize();
ret = call;
}
return ret;
@@ -1847,6 +1849,7 @@ void WasmBinaryBuilder::visitCallIndirect(CallIndirect *curr) {
curr->operands[num - i - 1] = popNonVoidExpression();
}
curr->type = fullType->result;
+ curr->finalize();
}
void WasmBinaryBuilder::visitGetLocal(GetLocal *curr) {
@@ -1873,6 +1876,7 @@ void WasmBinaryBuilder::visitSetLocal(SetLocal *curr, uint8_t code) {
curr->value = popNonVoidExpression();
curr->type = curr->value->type;
curr->setTee(code == BinaryConsts::TeeLocal);
+ curr->finalize();
}
void WasmBinaryBuilder::visitGetGlobal(GetGlobal *curr) {
@@ -1897,6 +1901,7 @@ void WasmBinaryBuilder::visitSetGlobal(SetGlobal *curr) {
auto index = getU32LEB();
curr->name = getGlobalName(index);
curr->value = popNonVoidExpression();
+ curr->finalize();
}
void WasmBinaryBuilder::readMemoryAccess(Address& alignment, size_t bytes, Address& offset) {
@@ -1926,6 +1931,7 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code) {
if (debug) std::cerr << "zz node: Load" << std::endl;
readMemoryAccess(curr->align, curr->bytes, curr->offset);
curr->ptr = popNonVoidExpression();
+ curr->finalize();
out = curr;
return true;
}
@@ -2149,6 +2155,7 @@ void WasmBinaryBuilder::visitUnreachable(Unreachable *curr) {
void WasmBinaryBuilder::visitDrop(Drop *curr) {
if (debug) std::cerr << "zz node: Drop" << std::endl;
curr->value = popNonVoidExpression();
+ curr->finalize();
}
} // namespace wasm
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 69509afec..f9e3912f7 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -928,6 +928,7 @@ Expression* SExpressionWasmBuilder::makeTeeLocal(Element& s) {
ret->index = getLocalIndex(*s[1]);
ret->value = parseExpression(s[2]);
ret->setTee(true);
+ ret->finalize();
return ret;
}
@@ -936,6 +937,7 @@ Expression* SExpressionWasmBuilder::makeSetLocal(Element& s) {
ret->index = getLocalIndex(*s[1]);
ret->value = parseExpression(s[2]);
ret->setTee(false);
+ ret->finalize();
return ret;
}
@@ -960,6 +962,7 @@ Expression* SExpressionWasmBuilder::makeSetGlobal(Element& s) {
ret->name = getGlobalName(*s[1]);
if (wasm.getGlobalOrNull(ret->name) && !wasm.getGlobalOrNull(ret->name)->mutable_) throw ParseException("set_global of immutable", s.line, s.col);
ret->value = parseExpression(s[2]);
+ ret->finalize();
return ret;
}
@@ -1084,6 +1087,7 @@ Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type) {
i++;
}
ret->ptr = parseExpression(s[i]);
+ ret->finalize();
return ret;
}
@@ -1210,6 +1214,7 @@ Expression* SExpressionWasmBuilder::makeCall(Element& s) {
ret->target = target;
ret->type = functionTypes[ret->target];
parseCallOperands(s, 2, s.size(), ret);
+ ret->finalize();
return ret;
}
@@ -1219,6 +1224,7 @@ Expression* SExpressionWasmBuilder::makeCallImport(Element& s) {
Import* import = wasm.getImport(ret->target);
ret->type = wasm.getFunctionType(import->functionType)->result;
parseCallOperands(s, 2, s.size(), ret);
+ ret->finalize();
return ret;
}
@@ -1232,6 +1238,7 @@ Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s) {
ret->type = fullType->result;
parseCallOperands(s, 2, s.size() - 1, ret);
ret->target = parseExpression(s[s.size() - 1]);
+ ret->finalize();
return ret;
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 96ca8fbc8..834d9e28f 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -198,6 +198,16 @@ void Block::finalize() {
if (!name.is()) {
// nothing branches here, so this is easy
if (list.size() > 0) {
+ // if we have an unreachable child, we are unreachable
+ // (we don't need to recurse into children, they can't
+ // break to us)
+ for (auto* child : list) {
+ if (child->type == unreachable) {
+ type = unreachable;
+ return;
+ }
+ }
+ // children are reachable, so last element determines type
type = list.back()->type;
} else {
type = none;
@@ -264,6 +274,31 @@ void Switch::finalize() {
type = unreachable;
}
+template<typename T>
+void handleUnreachableOperands(T* curr) {
+ for (auto* child : curr->operands) {
+ if (child->type == unreachable) {
+ curr->type = unreachable;
+ break;
+ }
+ }
+}
+
+void Call::finalize() {
+ handleUnreachableOperands(this);
+}
+
+void CallImport::finalize() {
+ handleUnreachableOperands(this);
+}
+
+void CallIndirect::finalize() {
+ handleUnreachableOperands(this);
+ if (target->type == unreachable) {
+ type = unreachable;
+ }
+}
+
bool FunctionType::structuralComparison(FunctionType& b) {
if (result != b.result) return false;
if (params.size() != b.params.size()) return false;
@@ -290,6 +325,24 @@ void SetLocal::setTee(bool is) {
else type = none;
}
+void SetLocal::finalize() {
+ if (value->type == unreachable) {
+ type = unreachable;
+ }
+}
+
+void SetGlobal::finalize() {
+ if (value->type == unreachable) {
+ type = unreachable;
+ }
+}
+
+void Load::finalize() {
+ if (ptr->type == unreachable) {
+ type = unreachable;
+ }
+}
+
void Store::finalize() {
assert(valueType != none); // must be set
if (ptr->type == unreachable || value->type == unreachable) {
@@ -423,6 +476,14 @@ void Select::finalize() {
}
}
+void Drop::finalize() {
+ if (value->type == unreachable) {
+ type = unreachable;
+ } else {
+ type = none;
+ }
+}
+
void Host::finalize() {
switch (op) {
case PageSize: case CurrentMemory: case HasFeature: {
diff --git a/test/passes/O.bin.txt b/test/passes/O.bin.txt
new file mode 100644
index 000000000..395c04369
--- /dev/null
+++ b/test/passes/O.bin.txt
@@ -0,0 +1,117 @@
+(module
+ (type $0 (func (param i64) (result i64)))
+ (memory $0 0)
+ (export "fac-rec" (func $0))
+ (export "fac-rec-named" (func $1))
+ (export "fac-iter" (func $2))
+ (export "fac-iter-named" (func $3))
+ (export "fac-opt" (func $4))
+ (func $0 (type $0) (param $0 i64) (result i64)
+ (if i64
+ (i64.eq
+ (get_local $0)
+ (i64.const 0)
+ )
+ (i64.const 1)
+ (i64.mul
+ (get_local $0)
+ (call $0
+ (i64.sub
+ (get_local $0)
+ (i64.const 1)
+ )
+ )
+ )
+ )
+ )
+ (func $1 (type $0) (param $0 i64) (result i64)
+ (if i64
+ (i64.eq
+ (get_local $0)
+ (i64.const 0)
+ )
+ (i64.const 1)
+ (i64.mul
+ (get_local $0)
+ (call $1
+ (i64.sub
+ (get_local $0)
+ (i64.const 1)
+ )
+ )
+ )
+ )
+ )
+ (func $2 (type $0) (param $0 i64) (result i64)
+ (if
+ (i64.eq
+ (get_local $0)
+ (i64.const 0)
+ )
+ (unreachable)
+ (unreachable)
+ )
+ )
+ (func $3 (type $0) (param $0 i64) (result i64)
+ (local $1 i64)
+ (set_local $1
+ (i64.const 1)
+ )
+ (block $label$1
+ (loop $label$2
+ (br_if $label$1
+ (i64.eq
+ (get_local $0)
+ (i64.const 0)
+ )
+ )
+ (set_local $1
+ (i64.mul
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (set_local $0
+ (i64.sub
+ (get_local $0)
+ (i64.const 1)
+ )
+ )
+ (br $label$2)
+ )
+ )
+ (get_local $1)
+ )
+ (func $4 (type $0) (param $0 i64) (result i64)
+ (local $1 i64)
+ (set_local $1
+ (i64.const 1)
+ )
+ (if
+ (i64.ge_s
+ (get_local $0)
+ (i64.const 2)
+ )
+ (loop $label$2
+ (set_local $1
+ (i64.mul
+ (get_local $1)
+ (get_local $0)
+ )
+ )
+ (br_if $label$2
+ (i64.gt_s
+ (tee_local $0
+ (i64.add
+ (get_local $0)
+ (i64.const -1)
+ )
+ )
+ (i64.const 1)
+ )
+ )
+ )
+ )
+ (get_local $1)
+ )
+)
diff --git a/test/passes/O.wasm b/test/passes/O.wasm
new file mode 100644
index 000000000..6dfd301de
--- /dev/null
+++ b/test/passes/O.wasm
Binary files differ
diff --git a/test/passes/dce.txt b/test/passes/dce.txt
index 98f0ea177..3ccdbdffd 100644
--- a/test/passes/dce.txt
+++ b/test/passes/dce.txt
@@ -361,22 +361,15 @@
)
)
(func $unreachable-brs-4 (type $3) (param $var$0 i32) (result i32)
- (i32.add
+ (drop
(i32.const 1)
- (block $label$0 i32
- (br $label$0
- (block $label$1 i32
- (drop
- (block
- (drop
- (i32.const 4104)
- )
- (unreachable)
- )
- )
- (unreachable)
- )
+ )
+ (drop
+ (block
+ (drop
+ (i32.const 4104)
)
+ (unreachable)
)
)
)
@@ -389,26 +382,24 @@
(block $label$0 i64
(get_local $var$1)
)
- (block $label$1 i64
- (block i64
- (drop
- (i64.sub
- (get_local $var$0)
- (i64.const 1)
- )
+ (block
+ (drop
+ (i64.sub
+ (get_local $var$0)
+ (i64.const 1)
)
- (block
- (drop
- (block $block i64
- (set_local $2
- (get_local $var$0)
- )
- (nop)
- (get_local $2)
+ )
+ (block
+ (drop
+ (block $block i64
+ (set_local $2
+ (get_local $var$0)
)
+ (nop)
+ (get_local $2)
)
- (unreachable)
)
+ (unreachable)
)
)
)
diff --git a/test/passes/dce_vacuum.bin.txt b/test/passes/dce_vacuum.bin.txt
new file mode 100644
index 000000000..8d365b327
--- /dev/null
+++ b/test/passes/dce_vacuum.bin.txt
@@ -0,0 +1,101 @@
+(module
+ (type $0 (func (param f32 f32) (result f32)))
+ (type $1 (func (param f64 f64) (result f64)))
+ (memory $0 0)
+ (export "f32.compute_radix" (func $0))
+ (export "f64.compute_radix" (func $1))
+ (func $0 (type $0) (param $var$0 f32) (param $var$1 f32) (result f32)
+ (block $label$0 f32
+ (loop $label$1
+ (br_if $label$1
+ (f32.eq
+ (f32.add
+ (f32.sub
+ (f32.add
+ (tee_local $var$0
+ (f32.add
+ (get_local $var$0)
+ (get_local $var$0)
+ )
+ )
+ (f32.const 1)
+ )
+ (get_local $var$0)
+ )
+ (f32.const -1)
+ )
+ (f32.const 0)
+ )
+ )
+ )
+ (drop
+ (block
+ (drop
+ (call $0
+ (f32.add
+ (get_local $var$0)
+ (tee_local $var$1
+ (f32.add
+ (get_local $var$1)
+ (f32.const 1)
+ )
+ )
+ )
+ (get_local $var$0)
+ )
+ )
+ (unreachable)
+ )
+ )
+ )
+ )
+ (func $1 (type $1) (param $var$0 f64) (param $var$1 f64) (result f64)
+ (block $label$0 f64
+ (loop $label$1
+ (br_if $label$1
+ (f64.eq
+ (f64.add
+ (f64.sub
+ (f64.add
+ (tee_local $var$0
+ (f64.add
+ (get_local $var$0)
+ (get_local $var$0)
+ )
+ )
+ (f64.const 1)
+ )
+ (get_local $var$0)
+ )
+ (f64.const -1)
+ )
+ (f64.const 0)
+ )
+ )
+ )
+ (loop $label$2
+ (br_if $label$2
+ (f64.ne
+ (f64.sub
+ (f64.sub
+ (f64.add
+ (get_local $var$0)
+ (tee_local $var$1
+ (f64.add
+ (get_local $var$1)
+ (f64.const 1)
+ )
+ )
+ )
+ (get_local $var$0)
+ )
+ (get_local $var$1)
+ )
+ (f64.const 0)
+ )
+ )
+ )
+ (get_local $var$1)
+ )
+ )
+)
diff --git a/test/passes/dce_vacuum.txt b/test/passes/dce_vacuum.txt
index 4fb982524..0f1ec5095 100644
--- a/test/passes/dce_vacuum.txt
+++ b/test/passes/dce_vacuum.txt
@@ -1,9 +1,28 @@
(module
(type $0 (func (result i32)))
+ (type $1 (func (param f32 f32) (result f32)))
+ (type $2 (func (param i64) (result i64)))
(memory $0 0)
(func $__Z12serveroptionPc (type $0) (result i32)
(return
(i32.const 0)
)
)
+ (func $drop-unreachable (type $1) (param $var$0 f32) (param $var$1 f32) (result f32)
+ (drop
+ (unreachable)
+ )
+ )
+ (func $set-unreachable (type $2) (param $var$0 i64) (result i64)
+ (local $var$1 i64)
+ (local $var$2 i64)
+ (if
+ (i64.eq
+ (get_local $var$1)
+ (i64.const 0)
+ )
+ (unreachable)
+ (unreachable)
+ )
+ )
)
diff --git a/test/passes/dce_vacuum.wasm b/test/passes/dce_vacuum.wasm
new file mode 100644
index 000000000..5fa1892bd
--- /dev/null
+++ b/test/passes/dce_vacuum.wasm
Binary files differ
diff --git a/test/passes/dce_vacuum.wast b/test/passes/dce_vacuum.wast
index a7e43db23..acddd76e9 100644
--- a/test/passes/dce_vacuum.wast
+++ b/test/passes/dce_vacuum.wast
@@ -10,5 +10,42 @@
(i32.const 0)
)
)
+ (func $drop-unreachable (param $var$0 f32) (param $var$1 f32) (result f32)
+ (block $label$0 f32
+ (loop $label$2
+ (drop
+ (unreachable)
+ )
+ (unreachable)
+ )
+ (get_local $var$1)
+ )
+ )
+
+ (func $set-unreachable (param $var$0 i64) (result i64)
+ (local $var$1 i64)
+ (local $var$2 i64)
+ (block $label$0 i64
+ (block $label$1
+ (loop $label$2
+ (if
+ (i64.eq
+ (get_local $var$1)
+ (i64.const 0)
+ )
+ (unreachable)
+ (set_local $var$2
+ (i64.mul
+ (unreachable)
+ (get_local $var$2)
+ )
+ )
+ )
+ (br $label$2)
+ )
+ )
+ (get_local $var$2)
+ )
+ )
)