diff options
-rwxr-xr-x | auto_update_tests.py | 2 | ||||
-rwxr-xr-x | check.py | 2 | ||||
-rw-r--r-- | src/s2wasm-main.cpp | 13 | ||||
-rw-r--r-- | src/s2wasm.h | 36 | ||||
-rw-r--r-- | test/dot_s/alias.wast | 6 | ||||
-rw-r--r-- | test/dot_s/basics.wast | 10 | ||||
-rw-r--r-- | test/dot_s/bcp-1.wast | 17 | ||||
-rw-r--r-- | test/dot_s/dyncall.c | 30 | ||||
-rw-r--r-- | test/dot_s/dyncall.s | 97 | ||||
-rw-r--r-- | test/dot_s/dyncall.wast | 84 | ||||
m--------- | test/emscripten | 0 |
11 files changed, 280 insertions, 17 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py index f0cba64ef..8cd2651ee 100755 --- a/auto_update_tests.py +++ b/auto_update_tests.py @@ -31,7 +31,7 @@ for dot_s_dir in ['dot_s', 'llvm_autogenerated']: wasm = s.replace('.s', '.wast') full = os.path.join('test', dot_s_dir, s) stack_alloc = ['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else [] - cmd = [os.path.join('bin', 's2wasm'), full] + stack_alloc + cmd = [os.path.join('bin', 's2wasm'), full, '--emscripten-glue'] + stack_alloc if s.startswith('start_'): cmd.append('--start') actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() @@ -476,7 +476,7 @@ for dot_s_dir in ['dot_s', 'llvm_autogenerated']: wasm = s.replace('.s', '.wast') full = os.path.join('test', dot_s_dir, s) stack_alloc = ['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else [] - cmd = [os.path.join('bin', 's2wasm'), full] + stack_alloc + cmd = [os.path.join('bin', 's2wasm'), full, '--emscripten-glue'] + stack_alloc if s.startswith('start_'): cmd.append('--start') actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp index d26ef3f1c..f22116978 100644 --- a/src/s2wasm-main.cpp +++ b/src/s2wasm-main.cpp @@ -29,6 +29,7 @@ using namespace wasm; int main(int argc, const char *argv[]) { bool ignoreUnknownSymbols = false; + bool generateEmscriptenGlue = false; std::string startFunction; Options options("s2wasm", "Link .s file into .wast"); options @@ -68,6 +69,11 @@ int main(int argc, const char *argv[]) { [](Options *o, const std::string &argument) { o->extra["max-memory"] = argument; }) + .add("--emscripten-glue", "-e", "Generate emscripten glue", + Options::Arguments::Zero, + [&generateEmscriptenGlue](Options *, const std::string &) { + generateEmscriptenGlue = true; + }) .add_positional("INFILE", Options::Arguments::One, [](Options *o, const std::string &argument) { o->extra["infile"] = argument; @@ -98,9 +104,12 @@ int main(int argc, const char *argv[]) { stackAllocation, initialMem, maxMem, ignoreUnknownSymbols, startFunction); - if (options.debug) std::cerr << "Emscripten gluing..." << std::endl; std::stringstream meta; - s2wasm.emscriptenGlue(meta); + if (generateEmscriptenGlue) { + if (options.debug) std::cerr << "Emscripten gluing..." << std::endl; + // dyncall thunks + s2wasm.emscriptenGlue(meta); + } if (options.debug) std::cerr << "Printing..." << std::endl; Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release); diff --git a/src/s2wasm.h b/src/s2wasm.h index 2963af2fe..b78da8cfe 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -1249,20 +1249,28 @@ class S2WasmBuilder { wasm.addExport(exp); } - void getDyncallThunk(const std::string& sig) { - // hard-code the sig for testing for now. vi is the signature for static destructors - assert(sig == "vi"); - auto* targetType = ensureFunctionType(sig, &wasm, wasm.allocator); + void makeDynCallThunks() { + std::unordered_set<std::string> sigs; wasm::Builder wasmBuilder(wasm); - std::vector<NameType> params {{"$0", i32}, {"$1", i32}}; - Function* f = wasmBuilder.makeFunction(std::string("dynCall_") + sig, std::move(params), none, {}); - auto* call = wasmBuilder.makeCallIndirect( - targetType, - wasmBuilder.makeGetLocal(params[0].name, params[0].type), - {wasmBuilder.makeGetLocal(params[1].name, params[1].type)}); - auto* ret = wasmBuilder.makeReturn(call); - f->body = ret; - wasm.addFunction(f); + for (const auto& indirectFunc : wasm.table.names) { + std::string sig(getSig(wasm.getFunction(indirectFunc))); + auto* funcType = ensureFunctionType(sig, &wasm, wasm.allocator); + if (!sigs.insert(sig).second) continue; // Sig is already in the set + std::vector<NameType> params; + params.emplace_back("fptr", i32); // function pointer param + int p = 0; + for (const auto& ty : funcType->params) params.emplace_back("$" + std::to_string(p++), ty); + Function* f = wasmBuilder.makeFunction(std::string("dynCall_") + sig, std::move(params), funcType->result, {}); + Expression* fptr = wasmBuilder.makeGetLocal("fptr", i32); + std::vector<Expression*> args; + for (unsigned i = 0; i < funcType->params.size(); ++i) { + args.push_back(wasmBuilder.makeGetLocal("$" + std::to_string(i), funcType->params[i])); + } + Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, std::move(args)); + f->body = funcType->result == none ? call : wasmBuilder.makeReturn(call); + wasm.addFunction(f); + exportFunction(f->name, true); + } } void fix() { @@ -1383,6 +1391,8 @@ public: wasm.removeImport(EMSCRIPTEN_ASM_CONST); // we create _sig versions + makeDynCallThunks(); + o << ";; METADATA: { "; // find asmConst calls, and emit their metadata struct AsmConstWalker : public PostWalker<AsmConstWalker> { diff --git a/test/dot_s/alias.wast b/test/dot_s/alias.wast index c9c64117b..64a58a94c 100644 --- a/test/dot_s/alias.wast +++ b/test/dot_s/alias.wast @@ -4,6 +4,7 @@ (type $FUNCSIG$v (func)) (export "__exit" $__exit) (export "__needs_exit" $__needs_exit) + (export "dynCall_v" $dynCall_v) (table $__exit) (func $__exit (type $FUNCSIG$v) (local $$0 i32) @@ -15,5 +16,10 @@ (i32.const 0) ) ) + (func $dynCall_v (param $fptr i32) + (call_indirect $FUNCSIG$v + (get_local $fptr) + ) + ) ) ;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [] } diff --git a/test/dot_s/basics.wast b/test/dot_s/basics.wast index cc1af6c6e..bc3951633 100644 --- a/test/dot_s/basics.wast +++ b/test/dot_s/basics.wast @@ -9,6 +9,7 @@ (type $FUNCSIG$iii (func (param i32 i32) (result i32))) (import $puts "env" "puts" (param i32)) (export "main" $main) + (export "dynCall_iii" $dynCall_iii) (table $main) (func $main (type $FUNCSIG$iii) (param $$0 i32) (param $$1 i32) (result i32) (call_import $puts @@ -91,5 +92,14 @@ (get_local $$0) ) ) + (func $dynCall_iii (param $fptr i32) (param $$0 i32) (param $$1 i32) (result i32) + (return + (call_indirect $FUNCSIG$iii + (get_local $fptr) + (get_local $$0) + (get_local $$1) + ) + ) + ) ) ;; METADATA: { "asmConsts": {},"staticBump": 52, "initializers": [] } diff --git a/test/dot_s/bcp-1.wast b/test/dot_s/bcp-1.wast index 13f113932..4e3fa51ea 100644 --- a/test/dot_s/bcp-1.wast +++ b/test/dot_s/bcp-1.wast @@ -33,6 +33,8 @@ (export "opt1" $opt1) (export "opt2" $opt2) (export "main" $main) + (export "dynCall_i" $dynCall_i) + (export "dynCall_ii" $dynCall_ii) (table $bad0 $bad1 $bad5 $bad7 $bad8 $bad10 $bad2 $bad3 $bad6 $bad4 $bad9 $good0 $good1 $good2 $opt0 $opt1 $opt2) (func $bad0 (type $FUNCSIG$i) (result i32) (return @@ -305,5 +307,20 @@ (call_import $abort) (unreachable) ) + (func $dynCall_i (param $fptr i32) (result i32) + (return + (call_indirect $FUNCSIG$i + (get_local $fptr) + ) + ) + ) + (func $dynCall_ii (param $fptr i32) (param $$0 i32) (result i32) + (return + (call_indirect $FUNCSIG$ii + (get_local $fptr) + (get_local $$0) + ) + ) + ) ) ;; METADATA: { "asmConsts": {},"staticBump": 104, "initializers": [] } diff --git a/test/dot_s/dyncall.c b/test/dot_s/dyncall.c new file mode 100644 index 000000000..124b79d8b --- /dev/null +++ b/test/dot_s/dyncall.c @@ -0,0 +1,30 @@ +#include <stdint.h> + +/* Used to generate dyncall.s */ + +uint32_t i() { + return 0; +} +uint64_t jf(float f) { + return 0; +} +void vd(double d) { + return; +} +float ffjjdi(float f, uint64_t j, uint64_t j2, double d, uint32_t i) { + return 0.0; +} + +/* Duplicates sig vd */ +void vd2(double d) { + return; +} + +int main() { + asm(" i32.const $discard=, i@FUNCTION"); + asm(" i32.const $discard=, jf@FUNCTION"); + asm(" i32.const $discard=, vd@FUNCTION"); + asm(" i32.const $discard=, ffjjdi@FUNCTION"); + asm(" i32.const $discard=, vd2@FUNCTION"); + return 0; +} diff --git a/test/dot_s/dyncall.s b/test/dot_s/dyncall.s new file mode 100644 index 000000000..280a5bf37 --- /dev/null +++ b/test/dot_s/dyncall.s @@ -0,0 +1,97 @@ + .text + .file "src/work/binaryen/test/dot_s/dyncall.c" + .section .text.i,"ax",@progbits + .hidden i + .globl i + .type i,@function +i: # @i + .result i32 +# BB#0: # %entry + i32.const $push0=, 0 + return $pop0 + .endfunc +.Lfunc_end0: + .size i, .Lfunc_end0-i + + .section .text.jf,"ax",@progbits + .hidden jf + .globl jf + .type jf,@function +jf: # @jf + .param f32 + .result i64 +# BB#0: # %entry + i64.const $push0=, 0 + return $pop0 + .endfunc +.Lfunc_end1: + .size jf, .Lfunc_end1-jf + + .section .text.vd,"ax",@progbits + .hidden vd + .globl vd + .type vd,@function +vd: # @vd + .param f64 +# BB#0: # %entry + return + .endfunc +.Lfunc_end2: + .size vd, .Lfunc_end2-vd + + .section .text.ffjjdi,"ax",@progbits + .hidden ffjjdi + .globl ffjjdi + .type ffjjdi,@function +ffjjdi: # @ffjjdi + .param f32, i64, i64, f64, i32 + .result f32 +# BB#0: # %entry + f32.const $push0=, 0x0p0 + return $pop0 + .endfunc +.Lfunc_end3: + .size ffjjdi, .Lfunc_end3-ffjjdi + + .section .text.vd2,"ax",@progbits + .hidden vd2 + .globl vd2 + .type vd2,@function +vd2: # @vd2 + .param f64 +# BB#0: # %entry + return + .endfunc +.Lfunc_end4: + .size vd2, .Lfunc_end4-vd2 + + .section .text.main,"ax",@progbits + .hidden main + .globl main + .type main,@function +main: # @main + .result i32 +# BB#0: # %entry + #APP + i32.const $discard=, i@FUNCTION + #NO_APP + #APP + i32.const $discard=, jf@FUNCTION + #NO_APP + #APP + i32.const $discard=, vd@FUNCTION + #NO_APP + #APP + i32.const $discard=, ffjjdi@FUNCTION + #NO_APP + #APP + i32.const $discard=, vd2@FUNCTION + #NO_APP + i32.const $push0=, 0 + return $pop0 + .endfunc +.Lfunc_end5: + .size main, .Lfunc_end5-main + + + .ident "clang version 3.9.0 " diff --git a/test/dot_s/dyncall.wast b/test/dot_s/dyncall.wast new file mode 100644 index 000000000..3d82924f2 --- /dev/null +++ b/test/dot_s/dyncall.wast @@ -0,0 +1,84 @@ +(module + (memory 1) + (export "memory" memory) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$jf (func (param f32) (result i64))) + (type $FUNCSIG$vd (func (param f64))) + (type $FUNCSIG$ffjjdi (func (param f32 i64 i64 f64 i32) (result f32))) + (export "i" $i) + (export "jf" $jf) + (export "vd" $vd) + (export "ffjjdi" $ffjjdi) + (export "vd2" $vd2) + (export "main" $main) + (export "dynCall_i" $dynCall_i) + (export "dynCall_jf" $dynCall_jf) + (export "dynCall_vd" $dynCall_vd) + (export "dynCall_ffjjdi" $dynCall_ffjjdi) + (table $i $jf $vd $ffjjdi $vd2) + (func $i (type $FUNCSIG$i) (result i32) + (return + (i32.const 0) + ) + ) + (func $jf (type $FUNCSIG$jf) (param $$0 f32) (result i64) + (return + (i64.const 0) + ) + ) + (func $vd (type $FUNCSIG$vd) (param $$0 f64) + (return) + ) + (func $ffjjdi (type $FUNCSIG$ffjjdi) (param $$0 f32) (param $$1 i64) (param $$2 i64) (param $$3 f64) (param $$4 i32) (result f32) + (return + (f32.const 0) + ) + ) + (func $vd2 (type $FUNCSIG$vd) (param $$0 f64) + (return) + ) + (func $main (result i32) + (i32.const 0) + (i32.const 1) + (i32.const 2) + (i32.const 3) + (i32.const 4) + (return + (i32.const 0) + ) + ) + (func $dynCall_i (param $fptr i32) (result i32) + (return + (call_indirect $FUNCSIG$i + (get_local $fptr) + ) + ) + ) + (func $dynCall_jf (param $fptr i32) (param $$0 f32) (result i64) + (return + (call_indirect $FUNCSIG$jf + (get_local $fptr) + (get_local $$0) + ) + ) + ) + (func $dynCall_vd (param $fptr i32) (param $$0 f64) + (call_indirect $FUNCSIG$vd + (get_local $fptr) + (get_local $$0) + ) + ) + (func $dynCall_ffjjdi (param $fptr i32) (param $$0 f32) (param $$1 i64) (param $$2 i64) (param $$3 f64) (param $$4 i32) (result f32) + (return + (call_indirect $FUNCSIG$ffjjdi + (get_local $fptr) + (get_local $$0) + (get_local $$1) + (get_local $$2) + (get_local $$3) + (get_local $$4) + ) + ) + ) +) +;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [] } diff --git a/test/emscripten b/test/emscripten -Subproject e480c6ed0194fc72c866c9d2eef697c221d1ae2 +Subproject b8420785844ae400de98ddb41db6bdfd7a227da |