diff options
-rwxr-xr-x | auto_update_tests.py | 2 | ||||
-rwxr-xr-x | check.py | 6 | ||||
-rw-r--r-- | src/js/wasm.js-post.js | 2 | ||||
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 17 | ||||
-rw-r--r-- | src/support/archive.cpp | 4 | ||||
-rw-r--r-- | src/wasm-linker.cpp | 38 | ||||
-rw-r--r-- | src/wasm.h | 34 | ||||
-rw-r--r-- | test/linker/archive/bar.s | 5 | ||||
-rw-r--r-- | test/linker/archive/foobar.a | 24 | ||||
-rw-r--r-- | test/linker/bar.c | 4 | ||||
-rw-r--r-- | test/linker/quux.c | 1 | ||||
-rw-r--r-- | test/passes/simplify-locals.txt | 19 | ||||
-rw-r--r-- | test/passes/simplify-locals.wast | 19 |
13 files changed, 137 insertions, 38 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py index 7162bd8fd..d435dcdaf 100755 --- a/auto_update_tests.py +++ b/auto_update_tests.py @@ -2,7 +2,7 @@ import os, sys, subprocess, difflib -os.environ['LD_LIBRARY_PATH'] = 'lib' # find our dynamic libraries +os.environ['LD_LIBRARY_PATH'] += os.pathsep + 'lib' # find our dynamic libraries print '[ processing and updating testcases... ]\n' @@ -49,7 +49,7 @@ WATERFALL_BUILD_DIR = os.path.join(BASE_DIR, 'wasm-install') BIN_DIR = os.path.abspath(os.path.join(WATERFALL_BUILD_DIR, 'wasm-install', 'bin')) os.environ['BINARYEN'] = os.getcwd() -os.environ['LD_LIBRARY_PATH'] = 'lib' # find our dynamic libraries +os.environ['LD_LIBRARY_PATH'] += os.pathsep + 'lib' # find our dynamic libraries def fetch_waterfall(): rev = open(os.path.join('test', 'revision')).read().strip() @@ -500,7 +500,7 @@ for dot_s_dir in ['dot_s', 'llvm_autogenerated']: print '\n[ running linker tests... ]\n' # The {main,foo,bar,baz}.s files were created by running clang over the respective # c files. The foobar.bar archive was created by running: -# llvm-ar -format=gnu rc foobar.a foo.s bar.s baz.s +# llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s s2wasm = os.path.join('bin', 's2wasm') cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '-l', os.path.join('test', 'linker', 'archive', 'foobar.a')] output = run_command(cmd) @@ -509,6 +509,8 @@ fail_if_not_contained(output, '(func $foo') fail_if_not_contained(output, '(i32.const 42)') # bar should be linked in from bar.s fail_if_not_contained(output, '(func $bar') +# quux should be linked in from bar.s even though it comes before bar.s in the archive +fail_if_not_contained(output, '(func $quux') # baz should not be linked in at all if 'baz' in output: raise Exception('output should not contain "baz": ' + output) diff --git a/src/js/wasm.js-post.js b/src/js/wasm.js-post.js index a0c026c91..6d73981f1 100644 --- a/src/js/wasm.js-post.js +++ b/src/js/wasm.js-post.js @@ -188,7 +188,7 @@ function integrateWasmJS(Module) { info['env'] = env; var instance; try { - instance = Wasm.instantiateModule(getBinary(), info); + instance = Wasm['instantiateModule'](getBinary(), info); } catch (e) { Module['printErr']('failed to compile wasm module: ' + e); return false; diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index 785bccf06..fbd1e7e57 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -126,6 +126,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, for (auto target : sw->targets) { self->unoptimizableBlocks.insert(target); } + self->unoptimizableBlocks.insert(sw->default_); // TODO: we could use this info to stop gathering data on these blocks } self->sinkables.clear(); @@ -161,12 +162,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, // post-block cleanups if (curr->name.is()) { - unoptimizableBlocks.erase(curr->name); - } - if (hasBreaks) { - // more than one path to here, so nonlinear - sinkables.clear(); - blockBreaks.erase(curr->name); + if (unoptimizableBlocks.count(curr->name)) { + sinkables.clear(); + unoptimizableBlocks.erase(curr->name); + } + + if (hasBreaks) { + // more than one path to here, so nonlinear + sinkables.clear(); + blockBreaks.erase(curr->name); + } } } diff --git a/src/support/archive.cpp b/src/support/archive.cpp index c0351bc05..126f4e2ce 100644 --- a/src/support/archive.cpp +++ b/src/support/archive.cpp @@ -210,8 +210,8 @@ static uint32_t read32be(const uint8_t* buf) { } void Archive::dump() const { - printf("Archive data %p len %lu, firstRegularData %p\n", data.data(), - (long unsigned)data.size(), firstRegularData); + printf("Archive data %p len %zu, firstRegularData %p\n", data.data(), + data.size(), firstRegularData); printf("Symbol table %p, len %u\n", symbolTable.data, symbolTable.len); printf("string table %p, len %u\n", stringTable.data, stringTable.len); const uint8_t* buf = symbolTable.data; diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp index f4f516073..a4bd97e2f 100644 --- a/src/wasm-linker.cpp +++ b/src/wasm-linker.cpp @@ -217,23 +217,31 @@ bool Linker::linkObject(S2WasmBuilder& builder) { } bool Linker::linkArchive(Archive& archive) { - for (auto child = archive.child_begin(), end = archive.child_end(); - child != end; ++child) { - Archive::SubBuffer memberBuf = child->getBuffer(); - // S2WasmBuilder expects its input to be NUL-terminated. Archive members are - // not NUL-terminated. So we have to copy the contents out before parsing. - std::vector<char> memberString(memberBuf.len + 1); - memcpy(memberString.data(), memberBuf.data, memberBuf.len); - memberString[memberBuf.len] = '\0'; - S2WasmBuilder memberBuilder(memberString.data(), false); - auto* memberSymbols = memberBuilder.getSymbolInfo(); - for (const Name& symbol : memberSymbols->implementedFunctions) { - if (out.symbolInfo.undefinedFunctions.count(symbol)) { - if (!linkObject(memberBuilder)) return false; - break; + bool selected; + do { + selected = false; + for (auto child = archive.child_begin(), end = archive.child_end(); + child != end; ++child) { + Archive::SubBuffer memberBuf = child->getBuffer(); + // S2WasmBuilder expects its input to be NUL-terminated. Archive members + // are + // not NUL-terminated. So we have to copy the contents out before parsing. + std::vector<char> memberString(memberBuf.len + 1); + memcpy(memberString.data(), memberBuf.data, memberBuf.len); + memberString[memberBuf.len] = '\0'; + S2WasmBuilder memberBuilder(memberString.data(), false); + auto* memberSymbols = memberBuilder.getSymbolInfo(); + for (const Name& symbol : memberSymbols->implementedFunctions) { + if (out.symbolInfo.undefinedFunctions.count(symbol)) { + if (!linkObject(memberBuilder)) return false; + selected = true; + break; + } } } - } + // If we selected an archive member, it may depend on another archive member + // so continue to make passes over the members until no more are added. + } while (selected); return true; } diff --git a/src/wasm.h b/src/wasm.h index f7ed6b42f..dff0bcd5a 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -246,11 +246,37 @@ private: } } + static uint32_t NaNPayload(float f) { + assert(std::isnan(f) && "expected a NaN"); + // SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + // NaN has all-one exponent and non-zero fraction. + return ~0xff800000u & bit_cast<uint32_t>(f); + } + + static uint64_t NaNPayload(double f) { + assert(std::isnan(f) && "expected a NaN"); + // SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF + // NaN has all-one exponent and non-zero fraction. + return ~0xfff0000000000000ull & bit_cast<uint64_t>(f); + } + + static float setQuietNaN(float f) { + assert(std::isnan(f) && "expected a NaN"); + // An SNaN is a NaN with the most significant fraction bit clear. + return bit_cast<float>(0x00400000u | bit_cast<uint32_t>(f)); + } + + static double setQuietNaN(double f) { + assert(std::isnan(f) && "expected a NaN"); + // An SNaN is a NaN with the most significant fraction bit clear. + return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f)); + } + static void printFloat(std::ostream &o, float f) { if (std::isnan(f)) { const char *sign = std::signbit(f) ? "-" : ""; o << sign << "nan"; - if (uint32_t payload = ~0xff800000u & bit_cast<uint32_t>(f)) { + if (uint32_t payload = NaNPayload(f)) { o << ":0x" << std::hex << payload << std::dec; } return; @@ -266,7 +292,7 @@ private: if (std::isnan(d)) { const char *sign = std::signbit(d) ? "-" : ""; o << sign << "nan"; - if (uint64_t payload = ~0xfff0000000000000ull & bit_cast<uint64_t>(d)) { + if (uint64_t payload = NaNPayload(d)) { o << ":0x" << std::hex << payload << std::dec; } return; @@ -448,7 +474,7 @@ private: switch (std::fpclassify(rhs)) { case FP_ZERO: switch (std::fpclassify(lhs)) { - case FP_NAN: return *this; + case FP_NAN: return Literal(setQuietNaN(lhs)); case FP_ZERO: return Literal(std::copysign(std::numeric_limits<float>::quiet_NaN(), sign)); case FP_NORMAL: // fallthrough case FP_SUBNORMAL: // fallthrough @@ -468,7 +494,7 @@ private: switch (std::fpclassify(rhs)) { case FP_ZERO: switch (std::fpclassify(lhs)) { - case FP_NAN: return *this; + case FP_NAN: return Literal(setQuietNaN(lhs)); case FP_ZERO: return Literal(std::copysign(std::numeric_limits<double>::quiet_NaN(), sign)); case FP_NORMAL: // fallthrough case FP_SUBNORMAL: // fallthrough diff --git a/test/linker/archive/bar.s b/test/linker/archive/bar.s index 7c39347e0..5012d4f14 100644 --- a/test/linker/archive/bar.s +++ b/test/linker/archive/bar.s @@ -1,15 +1,16 @@ .text - .file "src/work/binaryen/test/linker/archive/bar.c" + .file "test/linker/bar.c" .section .text.bar,"ax",@progbits .hidden bar .globl bar .type bar,@function bar: # @bar # BB#0: # %entry + call quux@FUNCTION return .endfunc .Lfunc_end0: .size bar, .Lfunc_end0-bar - .ident "clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)" + .ident "clang version 3.9.0 (trunk 268553) (llvm/trunk 268561)" diff --git a/test/linker/archive/foobar.a b/test/linker/archive/foobar.a index 6028e8ce5..0da380708 100644 --- a/test/linker/archive/foobar.a +++ b/test/linker/archive/foobar.a @@ -1,4 +1,21 @@ !<arch> +quux.s/ 0 0 0 644 345 ` + .text + .file "test/linker/quux.c" + .section .text.quux,"ax",@progbits + .hidden quux + .globl quux + .type quux,@function +quux: # @quux +# BB#0: # %entry + return + .endfunc +.Lfunc_end0: + .size quux, .Lfunc_end0-quux + + + .ident "clang version 3.9.0 (trunk 268553) (llvm/trunk 268561)" + foo.s/ 0 0 0 644 407 ` .text .file "src/work/binaryen/test/linker/foo.c" @@ -19,22 +36,23 @@ foo: # @foo .ident "clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)" -bar.s/ 0 0 0 644 363 ` +bar.s/ 0 0 0 644 361 ` .text - .file "src/work/binaryen/test/linker/archive/bar.c" + .file "test/linker/bar.c" .section .text.bar,"ax",@progbits .hidden bar .globl bar .type bar,@function bar: # @bar # BB#0: # %entry + call quux@FUNCTION return .endfunc .Lfunc_end0: .size bar, .Lfunc_end0-bar - .ident "clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)" + .ident "clang version 3.9.0 (trunk 268553) (llvm/trunk 268561)" baz.s/ 0 0 0 644 355 ` .text diff --git a/test/linker/bar.c b/test/linker/bar.c index 0476ca2b0..8f32349da 100644 --- a/test/linker/bar.c +++ b/test/linker/bar.c @@ -1,2 +1,2 @@ -void bar() { -} +void quux(); +void bar() { quux(); } diff --git a/test/linker/quux.c b/test/linker/quux.c new file mode 100644 index 000000000..d9baa902a --- /dev/null +++ b/test/linker/quux.c @@ -0,0 +1 @@ +void quux() {} diff --git a/test/passes/simplify-locals.txt b/test/passes/simplify-locals.txt index cc84c35d5..d97e8fc33 100644 --- a/test/passes/simplify-locals.txt +++ b/test/passes/simplify-locals.txt @@ -517,4 +517,23 @@ (get_local $m) (get_local $t) ) + (func $switch-def (param $i3 i32) (result i32) + (local $i1 i32) + (set_local $i1 + (i32.const 10) + ) + (block $switch$def + (block $switch-case$1 + (br_table $switch-case$1 $switch$def + (get_local $i3) + ) + ) + (set_local $i1 + (i32.const 1) + ) + ) + (return + (get_local $i1) + ) + ) ) diff --git a/test/passes/simplify-locals.wast b/test/passes/simplify-locals.wast index 5f1db4bdb..521e8bac4 100644 --- a/test/passes/simplify-locals.wast +++ b/test/passes/simplify-locals.wast @@ -451,5 +451,24 @@ (get_local $s) (get_local $t) ) + (func $switch-def (param $i3 i32) (result i32) + (local $i1 i32) + (set_local $i1 + (i32.const 10) + ) + (block $switch$def + (block $switch-case$1 + (br_table $switch-case$1 $switch$def + (get_local $i3) + ) + ) + (set_local $i1 + (i32.const 1) + ) + ) + (return + (get_local $i1) + ) + ) ) |