From c42291948116b957642ea13e147342c362685ab4 Mon Sep 17 00:00:00 2001 From: l-m Date: Wed, 12 Jul 2023 12:24:38 +0000 Subject: [PATCH] wasm: remove dependency on thirdparty/binaryen, webassembly backend rewrite (#18120) --- .github/workflows/wasm_backend_tests_ci.yml | 58 +- .github/workflows/wasm_wabt_tests_ci.yml | 73 - cmd/tools/install_wabt.vsh | 0 cmd/v/v.v | 11 - vlib/builtin/wasm/builtin.v | 14 + vlib/builtin/wasm/wasi/builtin.v | 9 +- vlib/builtin/wasm/wasi/int.v | 15 +- vlib/builtin/wasm/wasi/wasi.v | 4 +- vlib/v/builder/compile.v | 37 +- vlib/v/gen/wasm/binaryen/binaryen.c.v | 3949 ------------------- vlib/v/gen/wasm/cast.v | 91 - vlib/v/gen/wasm/gen.v | 1860 +++++---- vlib/v/gen/wasm/mem.v | 1410 ++++--- vlib/v/gen/wasm/ops.v | 373 +- vlib/v/gen/wasm/serialisation.v | 168 - vlib/v/gen/wasm/serialise/alignment_test.v | 12 + vlib/v/gen/wasm/serialise/serialise.v | 449 +++ vlib/v/gen/wasm/tests/arith.vv | 57 + vlib/v/gen/wasm/tests/arith.vv.out | 29 + vlib/v/gen/wasm/tests/arrays.vv | 34 +- vlib/v/gen/wasm/tests/arrays.vv.out | 14 + vlib/v/gen/wasm/tests/builtin.vv | 17 +- vlib/v/gen/wasm/tests/builtin.vv.out | 6 + vlib/v/gen/wasm/tests/control_flow.vv | 37 +- vlib/v/gen/wasm/tests/control_flow.vv.out | 19 + vlib/v/gen/wasm/tests/misc.vv | 36 +- vlib/v/gen/wasm/tests/misc.vv.out | 17 + vlib/v/gen/wasm/tests/multi_expr.vv | 88 +- vlib/v/gen/wasm/tests/multi_expr.vv.out | 19 + vlib/v/gen/wasm/tests/structs.vv | 24 +- vlib/v/gen/wasm/tests/structs.vv.out | 10 + vlib/v/gen/wasm/tests/wasm_test.v | 22 +- vlib/v/help/build/build-wasm.txt | 25 + vlib/v/help/build/build.txt | 2 + vlib/v/pref/pref.v | 4 + vlib/v/transformer/transformer.v | 15 + vlib/v/util/util.v | 2 +- vlib/wasm/encoding.v | 26 +- vlib/wasm/functions.v | 7 + vlib/wasm/instructions.v | 18 +- 40 files changed, 2895 insertions(+), 6166 deletions(-) delete mode 100644 .github/workflows/wasm_wabt_tests_ci.yml mode change 100644 => 100755 cmd/tools/install_wabt.vsh delete mode 100644 vlib/v/gen/wasm/binaryen/binaryen.c.v delete mode 100644 vlib/v/gen/wasm/cast.v delete mode 100644 vlib/v/gen/wasm/serialisation.v create mode 100644 vlib/v/gen/wasm/serialise/alignment_test.v create mode 100644 vlib/v/gen/wasm/serialise/serialise.v create mode 100644 vlib/v/gen/wasm/tests/arith.vv.out create mode 100644 vlib/v/gen/wasm/tests/arrays.vv.out create mode 100644 vlib/v/gen/wasm/tests/builtin.vv.out create mode 100644 vlib/v/gen/wasm/tests/control_flow.vv.out create mode 100644 vlib/v/gen/wasm/tests/misc.vv.out create mode 100644 vlib/v/gen/wasm/tests/multi_expr.vv.out create mode 100644 vlib/v/gen/wasm/tests/structs.vv.out create mode 100644 vlib/v/help/build/build-wasm.txt diff --git a/.github/workflows/wasm_backend_tests_ci.yml b/.github/workflows/wasm_backend_tests_ci.yml index 460ec0f6a0..753e6fef9c 100644 --- a/.github/workflows/wasm_backend_tests_ci.yml +++ b/.github/workflows/wasm_backend_tests_ci.yml @@ -60,8 +60,10 @@ jobs: - name: Build V run: make -j4 && ./v symlink -githubci - - name: Install binaryen as build dependency for the V WASM backend - run: ./v cmd/tools/install_binaryen.vsh + - name: Install wasmer to execute WASM modules + run: | + curl https://get.wasmer.io -sSfL | sh + sudo ln -s ~/.wasmer/bin/wasmer /usr/local/bin - name: Build the V WASM backend run: ./v -cc clang -showcc -v cmd/tools/builders/wasm_builder.v @@ -82,8 +84,10 @@ jobs: - name: Build V run: make -j4 && ./v symlink -githubci - - name: Install binaryen as build dependency for the V WASM backend - run: ./v cmd/tools/install_binaryen.vsh + - name: Install wasmer to execute WASM modules + run: | + curl https://get.wasmer.io -sSfL | sh + sudo ln -s ~/.wasmer/bin/wasmer /usr/local/bin - name: Build the V WASM backend run: ./v -cc clang -showcc -v cmd/tools/builders/wasm_builder.v @@ -94,26 +98,26 @@ jobs: - name: Build examples run: VTEST_ONLY=wasm ./v build-examples - wasm-backend-windows: - runs-on: windows-2022 - if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' - timeout-minutes: 121 - steps: - - uses: actions/checkout@v3 - - - name: Build V - run: .\make.bat -msvc - - name: Symlink V - run: .\v.exe symlink -githubci - - - name: Install binaryen as build dependency for the V WASM backend - run: v cmd/tools/install_binaryen.vsh - - - name: Build the V WASM backend - run: v -cc msvc -showcc -v cmd/tools/builders/wasm_builder.v - - - name: Test the WASM backend - run: v -stats test vlib/v/gen/wasm/tests/ - - - name: Build examples - run: $env:VTEST_ONLY='wasm'; v build-examples +# wasm-backend-windows: +# runs-on: windows-2022 +# if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' +# timeout-minutes: 121 +# steps: +# - uses: actions/checkout@v3 +# +# - name: Build V +# run: .\make.bat -msvc +# - name: Symlink V +# run: .\v.exe symlink -githubci +# +# - name: Install binaryen as build dependency for the V WASM backend +# run: v cmd/tools/install_binaryen.vsh +# +# - name: Build the V WASM backend +# run: v -cc msvc -showcc -v cmd/tools/builders/wasm_builder.v +# +# - name: Test the WASM backend +# run: v -stats test vlib/v/gen/wasm/tests/ +# +# - name: Build examples +# run: $env:VTEST_ONLY='wasm'; v build-examples diff --git a/.github/workflows/wasm_wabt_tests_ci.yml b/.github/workflows/wasm_wabt_tests_ci.yml deleted file mode 100644 index 868d7deeb3..0000000000 --- a/.github/workflows/wasm_wabt_tests_ci.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: wasm wabt validate tests CI - -on: - push: - paths: - - '!**' - - '!**.md' - - 'vlib/builtin/**.v' - - 'vlib/wasm/**.v' - - 'vlib/wasm/tests/**.v' - pull_request: - paths: - - '!**' - - '!**.md' - - 'vlib/builtin/**.v' - - 'vlib/wasm/**.v' - - 'vlib/wasm/tests/**.v' - -concurrency: - group: wasm-wabt-ci-${{ github.event.pull_request.number || github.sha }} - cancel-in-progress: true - -jobs: - wasm-wabt-ubuntu: - runs-on: ubuntu-22.04 - if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' - timeout-minutes: 31 - steps: - - uses: actions/checkout@v3 - - - name: Build V - run: make && ./v symlink -githubci - - - name: Install wabt to get the wasm-validate executable - run: v cmd/tools/install_wabt.vsh - - - name: Test the WASM backend - run: v test vlib/wasm/ - - wasm-wabt-macos: - runs-on: macOS-12 - if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' - timeout-minutes: 31 - steps: - - uses: actions/checkout@v3 - - - name: Build V - run: make && ./v symlink -githubci - - - name: Install wabt to get the wasm-validate executable - run: v cmd/tools/install_wabt.vsh - - - name: Test the WASM backend - run: v test vlib/wasm/ - - wasm-wabt-windows: - runs-on: windows-2022 - if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' - timeout-minutes: 31 - steps: - - uses: actions/checkout@v3 - - - name: Build V - run: .\make.bat -msvc - - - name: Symlink V - run: .\v.exe symlink -githubci - - - name: Install wabt to get the wasm-validate executable - run: v cmd/tools/install_wabt.vsh - - - name: Test the WASM backend - run: v test vlib/wasm/ diff --git a/cmd/tools/install_wabt.vsh b/cmd/tools/install_wabt.vsh old mode 100644 new mode 100755 diff --git a/cmd/v/v.v b/cmd/v/v.v index f7fde84f9d..fa2fb67bd7 100755 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -193,18 +193,7 @@ fn rebuild(prefs &pref.Preferences) { util.launch_tool(prefs.is_verbose, 'builders/golang_builder', os.args[1..]) } .wasm { - assert_wasm_backend_thirdparty() util.launch_tool(prefs.is_verbose, 'builders/wasm_builder', os.args[1..]) } } } - -fn assert_wasm_backend_thirdparty() { - vroot := os.dir(pref.vexe_path()) - if !os.exists('${vroot}/cmd/tools/builders/wasm_builder') - && !os.exists('${vroot}/thirdparty/binaryen') { - eprintln('The WebAssembly backend requires `binaryen`, an external library dependency') - eprintln('This can be installed with `./cmd/tools/install_binaryen.vsh`, to download prebuilt libraries for your platform') - exit(1) - } -} diff --git a/vlib/builtin/wasm/builtin.v b/vlib/builtin/wasm/builtin.v index 4f4eb11f2a..a40e39992e 100644 --- a/vlib/builtin/wasm/builtin.v +++ b/vlib/builtin/wasm/builtin.v @@ -6,6 +6,20 @@ fn __memory_grow(size usize) usize fn __memory_fill(dest &u8, value isize, size isize) fn __memory_copy(dest &u8, src &u8, size isize) +// add doc comments for the below functions + +// __reinterpret_f32_u32 converts a `u32` to a `f32` without changing the bit pattern. +pub fn __reinterpret_f32_u32(v f32) u32 + +// __reinterpret_u32_f32 converts a `f32` to a `u32` without changing the bit pattern. +pub fn __reinterpret_u32_f32(v u32) f32 + +// __reinterpret_f64_u64 converts a `u64` to a `f64` without changing the bit pattern. +pub fn __reinterpret_f64_u64(v f64) u64 + +// __reinterpret_u64_f64 converts a `f64` to a `u64` without changing the bit pattern. +pub fn __reinterpret_u64_f64(v u64) f64 + // vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap. // vcalloc returns a `byteptr` pointing to the memory address of the allocated space. // Unlike `v_calloc` vcalloc checks for negative values given in `n`. diff --git a/vlib/builtin/wasm/wasi/builtin.v b/vlib/builtin/wasm/wasi/builtin.v index fd14f293e9..e2a7d8b746 100644 --- a/vlib/builtin/wasm/wasi/builtin.v +++ b/vlib/builtin/wasm/wasi/builtin.v @@ -7,7 +7,7 @@ pub fn print(s string) { len: usize(s.len) } - WASM.fd_write(1, &elm, 1, -1) + WASM.fd_write(1, &elm, 1, 0) } // println prints a message with a line end, to stdout. @@ -20,7 +20,7 @@ pub fn println(s string) { len: 1 }]! - WASM.fd_write(1, &elm[0], 2, -1) + WASM.fd_write(1, &elm[0], 2, 0) } // eprint prints a message to stderr. @@ -30,7 +30,7 @@ pub fn eprint(s string) { len: usize(s.len) } - WASM.fd_write(2, &elm, 1, -1) + WASM.fd_write(2, &elm, 1, 0) } // eprintln prints a message with a line end, to stderr. @@ -43,7 +43,7 @@ pub fn eprintln(s string) { len: 1 }]! - WASM.fd_write(2, &elm[0], 2, -1) + WASM.fd_write(2, &elm[0], 2, 0) } // exit terminates execution immediately and returns exit `code` to the shell. @@ -57,6 +57,5 @@ pub fn exit(code int) { pub fn panic(s string) { eprint('V panic: ') eprintln(s) - _ := *&u8(-1) exit(1) } diff --git a/vlib/builtin/wasm/wasi/int.v b/vlib/builtin/wasm/wasi/int.v index b526bd8612..eef4f64e5b 100644 --- a/vlib/builtin/wasm/wasi/int.v +++ b/vlib/builtin/wasm/wasi/int.v @@ -52,21 +52,18 @@ fn (nn int) str_l(max int) string { } diff := max - index vmemmove(buf, voidptr(buf + index), diff + 1) - /* - // === manual memory move for bare metal === - mut c:= 0 - for c < diff { - buf[c] = buf[c+index] - c++ - } - buf[c] = 0 - */ return tos(buf, diff) // return tos(memdup(&buf[0] + index, (max - index)), (max - index)) } } +// str returns the value of the `u8` as a `string`. +// Example: assert u8(2).str() == '2' +pub fn (n u8) str() string { + return int(n).str_l(5) +} + // str returns the value of the `i8` as a `string`. // Example: assert i8(-2).str() == '-2' pub fn (n i8) str() string { diff --git a/vlib/builtin/wasm/wasi/wasi.v b/vlib/builtin/wasm/wasi/wasi.v index 731b9e905e..123228785d 100644 --- a/vlib/builtin/wasm/wasi/wasi.v +++ b/vlib/builtin/wasm/wasi/wasi.v @@ -1,4 +1,3 @@ -[wasm_import_namespace: 'wasi_snapshot_preview1'] module builtin struct CIOVec { @@ -9,6 +8,9 @@ struct CIOVec { type Errno = u16 type FileDesc = int +[wasm_import_namespace: 'wasi_snapshot_preview1'] fn WASM.fd_write(fd FileDesc, iovs &CIOVec, iovs_len usize, retptr &usize) Errno + +[wasm_import_namespace: 'wasi_snapshot_preview1'] [noreturn] fn WASM.proc_exit(rval int) diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index 509a5f6b46..71d7db1ce4 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -82,12 +82,44 @@ fn (mut b Builder) run_compiled_executable_and_exit() { if !(b.pref.is_test || b.pref.is_run || b.pref.is_crun) { exit(0) } - compiled_file := os.real_path(b.pref.out_name) + mut compiled_file := b.pref.out_name + if b.pref.backend == .wasm && !compiled_file.ends_with('.wasm') { + compiled_file += '.wasm' + } + compiled_file = os.real_path(compiled_file) + + mut run_args := []string{cap: b.pref.run_args.len + 1} + run_file := if b.pref.backend.is_js() { node_basename := $if windows { 'node.exe' } $else { 'node' } os.find_abs_path_of_executable(node_basename) or { panic('Could not find `${node_basename}` in system path. Do you have Node.js installed?') } + } else if b.pref.backend == .wasm { + mut actual_run := ['wasmer', 'wasmtime', 'wavm', 'wasm3'] + mut actual_rf := '' + + // -autofree bug + // error: cannot convert 'struct string' to 'struct _option_string' + // mut actual_rf := ?string(none) + + for runtime in actual_run { + basename := $if windows { runtime + '.exe' } $else { runtime } + + if rf := os.find_abs_path_of_executable(basename) { + if basename == 'wavm' { + run_args << 'run' + } + actual_rf = rf + break + } + } + + if actual_rf == '' { + panic('Could not find `wasmer`, `wasmtime`, `wavm`, or `wasm3` in system path. Do you have any installed?') + } + + actual_rf } else if b.pref.backend == .golang { go_basename := $if windows { 'go.exe' } $else { 'go' } os.find_abs_path_of_executable(go_basename) or { @@ -96,8 +128,7 @@ fn (mut b Builder) run_compiled_executable_and_exit() { } else { compiled_file } - mut run_args := []string{cap: b.pref.run_args.len + 1} - if b.pref.backend.is_js() { + if b.pref.backend.is_js() || b.pref.backend == .wasm { run_args << compiled_file } else if b.pref.backend == .golang { run_args << ['run', compiled_file] diff --git a/vlib/v/gen/wasm/binaryen/binaryen.c.v b/vlib/v/gen/wasm/binaryen/binaryen.c.v deleted file mode 100644 index f6632d3193..0000000000 --- a/vlib/v/gen/wasm/binaryen/binaryen.c.v +++ /dev/null @@ -1,3949 +0,0 @@ -[translated] -module binaryen - -$if dynamic_binaryen ? { - #flag -lbinaryen -} $else { - #flag -lbinaryen - #flag -I@VEXEROOT/thirdparty/binaryen/include - #flag -L@VEXEROOT/thirdparty/binaryen/lib - - #flag darwin -lc++ -Wl,-rpath,"@executable_path/../../../thirdparty/binaryen/lib" - // the following, allows linking to the binaryen package from `brew install binaryen`, without having to run cmd/tools/install_binaryen.vsh first - #flag darwin -I/opt/homebrew/include -L/opt/homebrew/lib -Wl,-rpath,"/opt/homebrew/lib" - - #flag linux -lstdc++ -} - -type Index = u32 -type Type = u64 - -[c: 'BinaryenTypeNone'] -pub fn typenone() Type - -[c: 'BinaryenTypeInt32'] -pub fn typeint32() Type - -[c: 'BinaryenTypeInt64'] -pub fn typeint64() Type - -[c: 'BinaryenTypeFloat32'] -pub fn typefloat32() Type - -[c: 'BinaryenTypeFloat64'] -pub fn typefloat64() Type - -[c: 'BinaryenTypeVec128'] -pub fn typevec128() Type - -[c: 'BinaryenTypeFuncref'] -pub fn typefuncref() Type - -[c: 'BinaryenTypeExternref'] -pub fn typeexternref() Type - -[c: 'BinaryenTypeAnyref'] -pub fn typeanyref() Type - -[c: 'BinaryenTypeEqref'] -pub fn typeeqref() Type - -[c: 'BinaryenTypeI31ref'] -pub fn typei31ref() Type - -[c: 'BinaryenTypeStructref'] -pub fn typestructref() Type - -[c: 'BinaryenTypeArrayref'] -pub fn typearrayref() Type - -[c: 'BinaryenTypeStringref'] -pub fn typestringref() Type - -[c: 'BinaryenTypeStringviewWTF8'] -pub fn typestringviewwtf8() Type - -[c: 'BinaryenTypeStringviewWTF16'] -pub fn typestringviewwtf16() Type - -[c: 'BinaryenTypeStringviewIter'] -pub fn typestringviewiter() Type - -[c: 'BinaryenTypeNullref'] -pub fn typenullref() Type - -[c: 'BinaryenTypeNullExternref'] -pub fn typenullexternref() Type - -[c: 'BinaryenTypeNullFuncref'] -pub fn typenullfuncref() Type - -[c: 'BinaryenTypeUnreachable'] -pub fn typeunreachable() Type - -[c: 'BinaryenTypeAuto'] -pub fn typeauto() Type - -fn (t Type) str() string { - return match t { - typenone() { 'void' } - typeint32() { 'i32' } - typeint64() { 'i64' } - typefloat32() { 'f32' } - typefloat64() { 'f64' } - else { 'unknown binaryen type' } - } -} - -[c: 'BinaryenTypeCreate'] -pub fn typecreate(valuetypes &Type, numtypes Index) Type - -[c: 'BinaryenTypeArity'] -pub fn typearity(t Type) u32 - -[c: 'BinaryenTypeExpand'] -pub fn typeexpand(t Type, buf &Type) - -type PackedType = u32 - -[c: 'BinaryenPackedTypeNotPacked'] -pub fn packedtypenotpacked() PackedType - -[c: 'BinaryenPackedTypeInt8'] -pub fn packedtypeint8() PackedType - -[c: 'BinaryenPackedTypeInt16'] -pub fn packedtypeint16() PackedType - -type HeapType = &u32 - -[c: 'BinaryenHeapTypeExt'] -pub fn heaptypeext() HeapType - -[c: 'BinaryenHeapTypeFunc'] -pub fn heaptypefunc() HeapType - -[c: 'BinaryenHeapTypeAny'] -pub fn heaptypeany() HeapType - -[c: 'BinaryenHeapTypeEq'] -pub fn heaptypeeq() HeapType - -[c: 'BinaryenHeapTypeI31'] -pub fn heaptypei31() HeapType - -[c: 'BinaryenHeapTypeData'] -pub fn heaptypedata() HeapType - -[c: 'BinaryenHeapTypeArray'] -pub fn heaptypearray() HeapType - -[c: 'BinaryenHeapTypeString'] -pub fn heaptypestring() HeapType - -[c: 'BinaryenHeapTypeStringviewWTF8'] -pub fn heaptypestringviewwtf8() HeapType - -[c: 'BinaryenHeapTypeStringviewWTF16'] -pub fn heaptypestringviewwtf16() HeapType - -[c: 'BinaryenHeapTypeStringviewIter'] -pub fn heaptypestringviewiter() HeapType - -[c: 'BinaryenHeapTypeNone'] -pub fn heaptypenone() HeapType - -[c: 'BinaryenHeapTypeNoext'] -pub fn heaptypenoext() HeapType - -[c: 'BinaryenHeapTypeNofunc'] -pub fn heaptypenofunc() HeapType - -[c: 'BinaryenHeapTypeIsBasic'] -pub fn heaptypeisbasic(heaptype HeapType) bool - -[c: 'BinaryenHeapTypeIsSignature'] -pub fn heaptypeissignature(heaptype HeapType) bool - -[c: 'BinaryenHeapTypeIsStruct'] -pub fn heaptypeisstruct(heaptype HeapType) bool - -[c: 'BinaryenHeapTypeIsArray'] -pub fn heaptypeisarray(heaptype HeapType) bool - -[c: 'BinaryenHeapTypeIsBottom'] -pub fn heaptypeisbottom(heaptype HeapType) bool - -[c: 'BinaryenHeapTypeGetBottom'] -pub fn heaptypegetbottom(heaptype HeapType) HeapType - -[c: 'BinaryenHeapTypeIsSubType'] -pub fn heaptypeissubtype(left HeapType, right HeapType) bool - -[c: 'BinaryenStructTypeGetNumFields'] -pub fn structtypegetnumfields(heaptype HeapType) Index - -[c: 'BinaryenStructTypeGetFieldType'] -pub fn structtypegetfieldtype(heaptype HeapType, index Index) Type - -[c: 'BinaryenStructTypeGetFieldPackedType'] -pub fn structtypegetfieldpackedtype(heaptype HeapType, index Index) PackedType - -[c: 'BinaryenStructTypeIsFieldMutable'] -pub fn structtypeisfieldmutable(heaptype HeapType, index Index) bool - -[c: 'BinaryenArrayTypeGetElementType'] -pub fn arraytypegetelementtype(heaptype HeapType) Type - -[c: 'BinaryenArrayTypeGetElementPackedType'] -pub fn arraytypegetelementpackedtype(heaptype HeapType) PackedType - -[c: 'BinaryenArrayTypeIsElementMutable'] -pub fn arraytypeiselementmutable(heaptype HeapType) bool - -[c: 'BinaryenSignatureTypeGetParams'] -pub fn signaturetypegetparams(heaptype HeapType) Type - -[c: 'BinaryenSignatureTypeGetResults'] -pub fn signaturetypegetresults(heaptype HeapType) Type - -[c: 'BinaryenTypeGetHeapType'] -pub fn typegetheaptype(type_ Type) HeapType - -[c: 'BinaryenTypeIsNullable'] -pub fn typeisnullable(type_ Type) bool - -[c: 'BinaryenTypeFromHeapType'] -pub fn typefromheaptype(heaptype HeapType, nullable bool) Type - -type TypeSystem = u32 - -[c: 'BinaryenTypeSystemEquirecursive'] -pub fn typesystemequirecursive() TypeSystem - -[c: 'BinaryenTypeSystemNominal'] -pub fn typesystemnominal() TypeSystem - -[c: 'BinaryenTypeSystemIsorecursive'] -pub fn typesystemisorecursive() TypeSystem - -[c: 'BinaryenGetTypeSystem'] -pub fn gettypesystem() TypeSystem - -[c: 'BinaryenSetTypeSystem'] -pub fn settypesystem(typesystem TypeSystem) - -type ExpressionId = u32 - -[c: 'BinaryenInvalidId'] -pub fn invalidid() ExpressionId - -type ExternalKind = u32 - -[c: 'BinaryenExternalFunction'] -pub fn externalfunction() ExternalKind - -[c: 'BinaryenExternalTable'] -pub fn externaltable() ExternalKind - -[c: 'BinaryenExternalMemory'] -pub fn externalmemory() ExternalKind - -[c: 'BinaryenExternalGlobal'] -pub fn externalglobal() ExternalKind - -[c: 'BinaryenExternalTag'] -pub fn externaltag() ExternalKind - -type Features = u32 - -[c: 'BinaryenFeatureMVP'] -pub fn featuremvp() Features - -[c: 'BinaryenFeatureAtomics'] -pub fn featureatomics() Features - -[c: 'BinaryenFeatureBulkMemory'] -pub fn featurebulkmemory() Features - -[c: 'BinaryenFeatureMutableGlobals'] -pub fn featuremutableglobals() Features - -[c: 'BinaryenFeatureNontrappingFPToInt'] -pub fn featurenontrappingfptoint() Features - -[c: 'BinaryenFeatureSignExt'] -pub fn featuresignext() Features - -[c: 'BinaryenFeatureSIMD128'] -pub fn featuresimd128() Features - -[c: 'BinaryenFeatureExceptionHandling'] -pub fn featureexceptionhandling() Features - -[c: 'BinaryenFeatureTailCall'] -pub fn featuretailcall() Features - -[c: 'BinaryenFeatureReferenceTypes'] -pub fn featurereferencetypes() Features - -[c: 'BinaryenFeatureMultivalue'] -pub fn featuremultivalue() Features - -[c: 'BinaryenFeatureGC'] -pub fn featuregc() Features - -[c: 'BinaryenFeatureMemory64'] -pub fn featurememory64() Features - -[c: 'BinaryenFeatureRelaxedSIMD'] -pub fn featurerelaxedsimd() Features - -[c: 'BinaryenFeatureExtendedConst'] -pub fn featureextendedconst() Features - -[c: 'BinaryenFeatureStrings'] -pub fn featurestrings() Features - -[c: 'BinaryenFeatureMultiMemories'] -pub fn featuremultimemories() Features - -[c: 'BinaryenFeatureAll'] -pub fn featureall() Features - -type Module = voidptr - -[c: 'BinaryenModuleCreate'] -pub fn modulecreate() Module - -[c: 'BinaryenModuleDispose'] -pub fn moduledispose(module_ Module) - -union LiteralContainer { - i32_ int - i64_ i64 - f32_ f32 - f64_ f64 - v128 [16]u8 - func &char -} - -struct Literal { - type_ &u32 - lit LiteralContainer -} - -[c: 'BinaryenLiteralInt32'] -pub fn literalint32(x int) Literal - -[c: 'BinaryenLiteralInt64'] -pub fn literalint64(x i64) Literal - -[c: 'BinaryenLiteralFloat32'] -pub fn literalfloat32(x f32) Literal - -[c: 'BinaryenLiteralFloat64'] -pub fn literalfloat64(x f64) Literal - -[c: 'BinaryenLiteralVec128'] -pub fn literalvec128(x &u8) Literal - -[c: 'BinaryenLiteralFloat32Bits'] -pub fn literalfloat32bits(x int) Literal - -[c: 'BinaryenLiteralFloat64Bits'] -pub fn literalfloat64bits(x i64) Literal - -type Op = int - -[c: 'BinaryenClzInt32'] -pub fn clzint32() Op - -[c: 'BinaryenCtzInt32'] -pub fn ctzint32() Op - -[c: 'BinaryenPopcntInt32'] -pub fn popcntint32() Op - -[c: 'BinaryenNegFloat32'] -pub fn negfloat32() Op - -[c: 'BinaryenAbsFloat32'] -pub fn absfloat32() Op - -[c: 'BinaryenCeilFloat32'] -pub fn ceilfloat32() Op - -[c: 'BinaryenFloorFloat32'] -pub fn floorfloat32() Op - -[c: 'BinaryenTruncFloat32'] -pub fn truncfloat32() Op - -[c: 'BinaryenNearestFloat32'] -pub fn nearestfloat32() Op - -[c: 'BinaryenSqrtFloat32'] -pub fn sqrtfloat32() Op - -[c: 'BinaryenEqZInt32'] -pub fn eqzint32() Op - -[c: 'BinaryenClzInt64'] -pub fn clzint64() Op - -[c: 'BinaryenCtzInt64'] -pub fn ctzint64() Op - -[c: 'BinaryenPopcntInt64'] -pub fn popcntint64() Op - -[c: 'BinaryenNegFloat64'] -pub fn negfloat64() Op - -[c: 'BinaryenAbsFloat64'] -pub fn absfloat64() Op - -[c: 'BinaryenCeilFloat64'] -pub fn ceilfloat64() Op - -[c: 'BinaryenFloorFloat64'] -pub fn floorfloat64() Op - -[c: 'BinaryenTruncFloat64'] -pub fn truncfloat64() Op - -[c: 'BinaryenNearestFloat64'] -pub fn nearestfloat64() Op - -[c: 'BinaryenSqrtFloat64'] -pub fn sqrtfloat64() Op - -[c: 'BinaryenEqZInt64'] -pub fn eqzint64() Op - -[c: 'BinaryenExtendSInt32'] -pub fn extendsint32() Op - -[c: 'BinaryenExtendUInt32'] -pub fn extenduint32() Op - -[c: 'BinaryenWrapInt64'] -pub fn wrapint64() Op - -[c: 'BinaryenTruncSFloat32ToInt32'] -pub fn truncsfloat32toint32() Op - -[c: 'BinaryenTruncSFloat32ToInt64'] -pub fn truncsfloat32toint64() Op - -[c: 'BinaryenTruncUFloat32ToInt32'] -pub fn truncufloat32toint32() Op - -[c: 'BinaryenTruncUFloat32ToInt64'] -pub fn truncufloat32toint64() Op - -[c: 'BinaryenTruncSFloat64ToInt32'] -pub fn truncsfloat64toint32() Op - -[c: 'BinaryenTruncSFloat64ToInt64'] -pub fn truncsfloat64toint64() Op - -[c: 'BinaryenTruncUFloat64ToInt32'] -pub fn truncufloat64toint32() Op - -[c: 'BinaryenTruncUFloat64ToInt64'] -pub fn truncufloat64toint64() Op - -[c: 'BinaryenReinterpretFloat32'] -pub fn reinterpretfloat32() Op - -[c: 'BinaryenReinterpretFloat64'] -pub fn reinterpretfloat64() Op - -[c: 'BinaryenConvertSInt32ToFloat32'] -pub fn convertsint32tofloat32() Op - -[c: 'BinaryenConvertSInt32ToFloat64'] -pub fn convertsint32tofloat64() Op - -[c: 'BinaryenConvertUInt32ToFloat32'] -pub fn convertuint32tofloat32() Op - -[c: 'BinaryenConvertUInt32ToFloat64'] -pub fn convertuint32tofloat64() Op - -[c: 'BinaryenConvertSInt64ToFloat32'] -pub fn convertsint64tofloat32() Op - -[c: 'BinaryenConvertSInt64ToFloat64'] -pub fn convertsint64tofloat64() Op - -[c: 'BinaryenConvertUInt64ToFloat32'] -pub fn convertuint64tofloat32() Op - -[c: 'BinaryenConvertUInt64ToFloat64'] -pub fn convertuint64tofloat64() Op - -[c: 'BinaryenPromoteFloat32'] -pub fn promotefloat32() Op - -[c: 'BinaryenDemoteFloat64'] -pub fn demotefloat64() Op - -[c: 'BinaryenReinterpretInt32'] -pub fn reinterpretint32() Op - -[c: 'BinaryenReinterpretInt64'] -pub fn reinterpretint64() Op - -[c: 'BinaryenExtendS8Int32'] -pub fn extends8int32() Op - -[c: 'BinaryenExtendS16Int32'] -pub fn extends16int32() Op - -[c: 'BinaryenExtendS8Int64'] -pub fn extends8int64() Op - -[c: 'BinaryenExtendS16Int64'] -pub fn extends16int64() Op - -[c: 'BinaryenExtendS32Int64'] -pub fn extends32int64() Op - -[c: 'BinaryenAddInt32'] -pub fn addint32() Op - -[c: 'BinaryenSubInt32'] -pub fn subint32() Op - -[c: 'BinaryenMulInt32'] -pub fn mulint32() Op - -[c: 'BinaryenDivSInt32'] -pub fn divsint32() Op - -[c: 'BinaryenDivUInt32'] -pub fn divuint32() Op - -[c: 'BinaryenRemSInt32'] -pub fn remsint32() Op - -[c: 'BinaryenRemUInt32'] -pub fn remuint32() Op - -[c: 'BinaryenAndInt32'] -pub fn andint32() Op - -[c: 'BinaryenOrInt32'] -pub fn orint32() Op - -[c: 'BinaryenXorInt32'] -pub fn xorint32() Op - -[c: 'BinaryenShlInt32'] -pub fn shlint32() Op - -[c: 'BinaryenShrUInt32'] -pub fn shruint32() Op - -[c: 'BinaryenShrSInt32'] -pub fn shrsint32() Op - -[c: 'BinaryenRotLInt32'] -pub fn rotlint32() Op - -[c: 'BinaryenRotRInt32'] -pub fn rotrint32() Op - -[c: 'BinaryenEqInt32'] -pub fn eqint32() Op - -[c: 'BinaryenNeInt32'] -pub fn neint32() Op - -[c: 'BinaryenLtSInt32'] -pub fn ltsint32() Op - -[c: 'BinaryenLtUInt32'] -pub fn ltuint32() Op - -[c: 'BinaryenLeSInt32'] -pub fn lesint32() Op - -[c: 'BinaryenLeUInt32'] -pub fn leuint32() Op - -[c: 'BinaryenGtSInt32'] -pub fn gtsint32() Op - -[c: 'BinaryenGtUInt32'] -pub fn gtuint32() Op - -[c: 'BinaryenGeSInt32'] -pub fn gesint32() Op - -[c: 'BinaryenGeUInt32'] -pub fn geuint32() Op - -[c: 'BinaryenAddInt64'] -pub fn addint64() Op - -[c: 'BinaryenSubInt64'] -pub fn subint64() Op - -[c: 'BinaryenMulInt64'] -pub fn mulint64() Op - -[c: 'BinaryenDivSInt64'] -pub fn divsint64() Op - -[c: 'BinaryenDivUInt64'] -pub fn divuint64() Op - -[c: 'BinaryenRemSInt64'] -pub fn remsint64() Op - -[c: 'BinaryenRemUInt64'] -pub fn remuint64() Op - -[c: 'BinaryenAndInt64'] -pub fn andint64() Op - -[c: 'BinaryenOrInt64'] -pub fn orint64() Op - -[c: 'BinaryenXorInt64'] -pub fn xorint64() Op - -[c: 'BinaryenShlInt64'] -pub fn shlint64() Op - -[c: 'BinaryenShrUInt64'] -pub fn shruint64() Op - -[c: 'BinaryenShrSInt64'] -pub fn shrsint64() Op - -[c: 'BinaryenRotLInt64'] -pub fn rotlint64() Op - -[c: 'BinaryenRotRInt64'] -pub fn rotrint64() Op - -[c: 'BinaryenEqInt64'] -pub fn eqint64() Op - -[c: 'BinaryenNeInt64'] -pub fn neint64() Op - -[c: 'BinaryenLtSInt64'] -pub fn ltsint64() Op - -[c: 'BinaryenLtUInt64'] -pub fn ltuint64() Op - -[c: 'BinaryenLeSInt64'] -pub fn lesint64() Op - -[c: 'BinaryenLeUInt64'] -pub fn leuint64() Op - -[c: 'BinaryenGtSInt64'] -pub fn gtsint64() Op - -[c: 'BinaryenGtUInt64'] -pub fn gtuint64() Op - -[c: 'BinaryenGeSInt64'] -pub fn gesint64() Op - -[c: 'BinaryenGeUInt64'] -pub fn geuint64() Op - -[c: 'BinaryenAddFloat32'] -pub fn addfloat32() Op - -[c: 'BinaryenSubFloat32'] -pub fn subfloat32() Op - -[c: 'BinaryenMulFloat32'] -pub fn mulfloat32() Op - -[c: 'BinaryenDivFloat32'] -pub fn divfloat32() Op - -[c: 'BinaryenCopySignFloat32'] -pub fn copysignfloat32() Op - -[c: 'BinaryenMinFloat32'] -pub fn minfloat32() Op - -[c: 'BinaryenMaxFloat32'] -pub fn maxfloat32() Op - -[c: 'BinaryenEqFloat32'] -pub fn eqfloat32() Op - -[c: 'BinaryenNeFloat32'] -pub fn nefloat32() Op - -[c: 'BinaryenLtFloat32'] -pub fn ltfloat32() Op - -[c: 'BinaryenLeFloat32'] -pub fn lefloat32() Op - -[c: 'BinaryenGtFloat32'] -pub fn gtfloat32() Op - -[c: 'BinaryenGeFloat32'] -pub fn gefloat32() Op - -[c: 'BinaryenAddFloat64'] -pub fn addfloat64() Op - -[c: 'BinaryenSubFloat64'] -pub fn subfloat64() Op - -[c: 'BinaryenMulFloat64'] -pub fn mulfloat64() Op - -[c: 'BinaryenDivFloat64'] -pub fn divfloat64() Op - -[c: 'BinaryenCopySignFloat64'] -pub fn copysignfloat64() Op - -[c: 'BinaryenMinFloat64'] -pub fn minfloat64() Op - -[c: 'BinaryenMaxFloat64'] -pub fn maxfloat64() Op - -[c: 'BinaryenEqFloat64'] -pub fn eqfloat64() Op - -[c: 'BinaryenNeFloat64'] -pub fn nefloat64() Op - -[c: 'BinaryenLtFloat64'] -pub fn ltfloat64() Op - -[c: 'BinaryenLeFloat64'] -pub fn lefloat64() Op - -[c: 'BinaryenGtFloat64'] -pub fn gtfloat64() Op - -[c: 'BinaryenGeFloat64'] -pub fn gefloat64() Op - -[c: 'BinaryenAtomicRMWAdd'] -pub fn atomicrmwadd() Op - -[c: 'BinaryenAtomicRMWSub'] -pub fn atomicrmwsub() Op - -[c: 'BinaryenAtomicRMWAnd'] -pub fn atomicrmwand() Op - -[c: 'BinaryenAtomicRMWOr'] -pub fn atomicrmwor() Op - -[c: 'BinaryenAtomicRMWXor'] -pub fn atomicrmwxor() Op - -[c: 'BinaryenAtomicRMWXchg'] -pub fn atomicrmwxchg() Op - -[c: 'BinaryenTruncSatSFloat32ToInt32'] -pub fn truncsatsfloat32toint32() Op - -[c: 'BinaryenTruncSatSFloat32ToInt64'] -pub fn truncsatsfloat32toint64() Op - -[c: 'BinaryenTruncSatUFloat32ToInt32'] -pub fn truncsatufloat32toint32() Op - -[c: 'BinaryenTruncSatUFloat32ToInt64'] -pub fn truncsatufloat32toint64() Op - -[c: 'BinaryenTruncSatSFloat64ToInt32'] -pub fn truncsatsfloat64toint32() Op - -[c: 'BinaryenTruncSatSFloat64ToInt64'] -pub fn truncsatsfloat64toint64() Op - -[c: 'BinaryenTruncSatUFloat64ToInt32'] -pub fn truncsatufloat64toint32() Op - -[c: 'BinaryenTruncSatUFloat64ToInt64'] -pub fn truncsatufloat64toint64() Op - -[c: 'BinaryenSplatVecI8x16'] -pub fn splatveci8x16() Op - -[c: 'BinaryenExtractLaneSVecI8x16'] -pub fn extractlanesveci8x16() Op - -[c: 'BinaryenExtractLaneUVecI8x16'] -pub fn extractlaneuveci8x16() Op - -[c: 'BinaryenReplaceLaneVecI8x16'] -pub fn replacelaneveci8x16() Op - -[c: 'BinaryenSplatVecI16x8'] -pub fn splatveci16x8() Op - -[c: 'BinaryenExtractLaneSVecI16x8'] -pub fn extractlanesveci16x8() Op - -[c: 'BinaryenExtractLaneUVecI16x8'] -pub fn extractlaneuveci16x8() Op - -[c: 'BinaryenReplaceLaneVecI16x8'] -pub fn replacelaneveci16x8() Op - -[c: 'BinaryenSplatVecI32x4'] -pub fn splatveci32x4() Op - -[c: 'BinaryenExtractLaneVecI32x4'] -pub fn extractlaneveci32x4() Op - -[c: 'BinaryenReplaceLaneVecI32x4'] -pub fn replacelaneveci32x4() Op - -[c: 'BinaryenSplatVecI64x2'] -pub fn splatveci64x2() Op - -[c: 'BinaryenExtractLaneVecI64x2'] -pub fn extractlaneveci64x2() Op - -[c: 'BinaryenReplaceLaneVecI64x2'] -pub fn replacelaneveci64x2() Op - -[c: 'BinaryenSplatVecF32x4'] -pub fn splatvecf32x4() Op - -[c: 'BinaryenExtractLaneVecF32x4'] -pub fn extractlanevecf32x4() Op - -[c: 'BinaryenReplaceLaneVecF32x4'] -pub fn replacelanevecf32x4() Op - -[c: 'BinaryenSplatVecF64x2'] -pub fn splatvecf64x2() Op - -[c: 'BinaryenExtractLaneVecF64x2'] -pub fn extractlanevecf64x2() Op - -[c: 'BinaryenReplaceLaneVecF64x2'] -pub fn replacelanevecf64x2() Op - -[c: 'BinaryenEqVecI8x16'] -pub fn eqveci8x16() Op - -[c: 'BinaryenNeVecI8x16'] -pub fn neveci8x16() Op - -[c: 'BinaryenLtSVecI8x16'] -pub fn ltsveci8x16() Op - -[c: 'BinaryenLtUVecI8x16'] -pub fn ltuveci8x16() Op - -[c: 'BinaryenGtSVecI8x16'] -pub fn gtsveci8x16() Op - -[c: 'BinaryenGtUVecI8x16'] -pub fn gtuveci8x16() Op - -[c: 'BinaryenLeSVecI8x16'] -pub fn lesveci8x16() Op - -[c: 'BinaryenLeUVecI8x16'] -pub fn leuveci8x16() Op - -[c: 'BinaryenGeSVecI8x16'] -pub fn gesveci8x16() Op - -[c: 'BinaryenGeUVecI8x16'] -pub fn geuveci8x16() Op - -[c: 'BinaryenEqVecI16x8'] -pub fn eqveci16x8() Op - -[c: 'BinaryenNeVecI16x8'] -pub fn neveci16x8() Op - -[c: 'BinaryenLtSVecI16x8'] -pub fn ltsveci16x8() Op - -[c: 'BinaryenLtUVecI16x8'] -pub fn ltuveci16x8() Op - -[c: 'BinaryenGtSVecI16x8'] -pub fn gtsveci16x8() Op - -[c: 'BinaryenGtUVecI16x8'] -pub fn gtuveci16x8() Op - -[c: 'BinaryenLeSVecI16x8'] -pub fn lesveci16x8() Op - -[c: 'BinaryenLeUVecI16x8'] -pub fn leuveci16x8() Op - -[c: 'BinaryenGeSVecI16x8'] -pub fn gesveci16x8() Op - -[c: 'BinaryenGeUVecI16x8'] -pub fn geuveci16x8() Op - -[c: 'BinaryenEqVecI32x4'] -pub fn eqveci32x4() Op - -[c: 'BinaryenNeVecI32x4'] -pub fn neveci32x4() Op - -[c: 'BinaryenLtSVecI32x4'] -pub fn ltsveci32x4() Op - -[c: 'BinaryenLtUVecI32x4'] -pub fn ltuveci32x4() Op - -[c: 'BinaryenGtSVecI32x4'] -pub fn gtsveci32x4() Op - -[c: 'BinaryenGtUVecI32x4'] -pub fn gtuveci32x4() Op - -[c: 'BinaryenLeSVecI32x4'] -pub fn lesveci32x4() Op - -[c: 'BinaryenLeUVecI32x4'] -pub fn leuveci32x4() Op - -[c: 'BinaryenGeSVecI32x4'] -pub fn gesveci32x4() Op - -[c: 'BinaryenGeUVecI32x4'] -pub fn geuveci32x4() Op - -[c: 'BinaryenEqVecI64x2'] -pub fn eqveci64x2() Op - -[c: 'BinaryenNeVecI64x2'] -pub fn neveci64x2() Op - -[c: 'BinaryenLtSVecI64x2'] -pub fn ltsveci64x2() Op - -[c: 'BinaryenGtSVecI64x2'] -pub fn gtsveci64x2() Op - -[c: 'BinaryenLeSVecI64x2'] -pub fn lesveci64x2() Op - -[c: 'BinaryenGeSVecI64x2'] -pub fn gesveci64x2() Op - -[c: 'BinaryenEqVecF32x4'] -pub fn eqvecf32x4() Op - -[c: 'BinaryenNeVecF32x4'] -pub fn nevecf32x4() Op - -[c: 'BinaryenLtVecF32x4'] -pub fn ltvecf32x4() Op - -[c: 'BinaryenGtVecF32x4'] -pub fn gtvecf32x4() Op - -[c: 'BinaryenLeVecF32x4'] -pub fn levecf32x4() Op - -[c: 'BinaryenGeVecF32x4'] -pub fn gevecf32x4() Op - -[c: 'BinaryenEqVecF64x2'] -pub fn eqvecf64x2() Op - -[c: 'BinaryenNeVecF64x2'] -pub fn nevecf64x2() Op - -[c: 'BinaryenLtVecF64x2'] -pub fn ltvecf64x2() Op - -[c: 'BinaryenGtVecF64x2'] -pub fn gtvecf64x2() Op - -[c: 'BinaryenLeVecF64x2'] -pub fn levecf64x2() Op - -[c: 'BinaryenGeVecF64x2'] -pub fn gevecf64x2() Op - -[c: 'BinaryenNotVec128'] -pub fn notvec128() Op - -[c: 'BinaryenAndVec128'] -pub fn andvec128() Op - -[c: 'BinaryenOrVec128'] -pub fn orvec128() Op - -[c: 'BinaryenXorVec128'] -pub fn xorvec128() Op - -[c: 'BinaryenAndNotVec128'] -pub fn andnotvec128() Op - -[c: 'BinaryenBitselectVec128'] -pub fn bitselectvec128() Op - -[c: 'BinaryenAnyTrueVec128'] -pub fn anytruevec128() Op - -[c: 'BinaryenPopcntVecI8x16'] -pub fn popcntveci8x16() Op - -[c: 'BinaryenAbsVecI8x16'] -pub fn absveci8x16() Op - -[c: 'BinaryenNegVecI8x16'] -pub fn negveci8x16() Op - -[c: 'BinaryenAllTrueVecI8x16'] -pub fn alltrueveci8x16() Op - -[c: 'BinaryenBitmaskVecI8x16'] -pub fn bitmaskveci8x16() Op - -[c: 'BinaryenShlVecI8x16'] -pub fn shlveci8x16() Op - -[c: 'BinaryenShrSVecI8x16'] -pub fn shrsveci8x16() Op - -[c: 'BinaryenShrUVecI8x16'] -pub fn shruveci8x16() Op - -[c: 'BinaryenAddVecI8x16'] -pub fn addveci8x16() Op - -[c: 'BinaryenAddSatSVecI8x16'] -pub fn addsatsveci8x16() Op - -[c: 'BinaryenAddSatUVecI8x16'] -pub fn addsatuveci8x16() Op - -[c: 'BinaryenSubVecI8x16'] -pub fn subveci8x16() Op - -[c: 'BinaryenSubSatSVecI8x16'] -pub fn subsatsveci8x16() Op - -[c: 'BinaryenSubSatUVecI8x16'] -pub fn subsatuveci8x16() Op - -[c: 'BinaryenMinSVecI8x16'] -pub fn minsveci8x16() Op - -[c: 'BinaryenMinUVecI8x16'] -pub fn minuveci8x16() Op - -[c: 'BinaryenMaxSVecI8x16'] -pub fn maxsveci8x16() Op - -[c: 'BinaryenMaxUVecI8x16'] -pub fn maxuveci8x16() Op - -[c: 'BinaryenAvgrUVecI8x16'] -pub fn avgruveci8x16() Op - -[c: 'BinaryenAbsVecI16x8'] -pub fn absveci16x8() Op - -[c: 'BinaryenNegVecI16x8'] -pub fn negveci16x8() Op - -[c: 'BinaryenAllTrueVecI16x8'] -pub fn alltrueveci16x8() Op - -[c: 'BinaryenBitmaskVecI16x8'] -pub fn bitmaskveci16x8() Op - -[c: 'BinaryenShlVecI16x8'] -pub fn shlveci16x8() Op - -[c: 'BinaryenShrSVecI16x8'] -pub fn shrsveci16x8() Op - -[c: 'BinaryenShrUVecI16x8'] -pub fn shruveci16x8() Op - -[c: 'BinaryenAddVecI16x8'] -pub fn addveci16x8() Op - -[c: 'BinaryenAddSatSVecI16x8'] -pub fn addsatsveci16x8() Op - -[c: 'BinaryenAddSatUVecI16x8'] -pub fn addsatuveci16x8() Op - -[c: 'BinaryenSubVecI16x8'] -pub fn subveci16x8() Op - -[c: 'BinaryenSubSatSVecI16x8'] -pub fn subsatsveci16x8() Op - -[c: 'BinaryenSubSatUVecI16x8'] -pub fn subsatuveci16x8() Op - -[c: 'BinaryenMulVecI16x8'] -pub fn mulveci16x8() Op - -[c: 'BinaryenMinSVecI16x8'] -pub fn minsveci16x8() Op - -[c: 'BinaryenMinUVecI16x8'] -pub fn minuveci16x8() Op - -[c: 'BinaryenMaxSVecI16x8'] -pub fn maxsveci16x8() Op - -[c: 'BinaryenMaxUVecI16x8'] -pub fn maxuveci16x8() Op - -[c: 'BinaryenAvgrUVecI16x8'] -pub fn avgruveci16x8() Op - -[c: 'BinaryenQ15MulrSatSVecI16x8'] -pub fn q15mulrsatsveci16x8() Op - -[c: 'BinaryenExtMulLowSVecI16x8'] -pub fn extmullowsveci16x8() Op - -[c: 'BinaryenExtMulHighSVecI16x8'] -pub fn extmulhighsveci16x8() Op - -[c: 'BinaryenExtMulLowUVecI16x8'] -pub fn extmullowuveci16x8() Op - -[c: 'BinaryenExtMulHighUVecI16x8'] -pub fn extmulhighuveci16x8() Op - -[c: 'BinaryenAbsVecI32x4'] -pub fn absveci32x4() Op - -[c: 'BinaryenNegVecI32x4'] -pub fn negveci32x4() Op - -[c: 'BinaryenAllTrueVecI32x4'] -pub fn alltrueveci32x4() Op - -[c: 'BinaryenBitmaskVecI32x4'] -pub fn bitmaskveci32x4() Op - -[c: 'BinaryenShlVecI32x4'] -pub fn shlveci32x4() Op - -[c: 'BinaryenShrSVecI32x4'] -pub fn shrsveci32x4() Op - -[c: 'BinaryenShrUVecI32x4'] -pub fn shruveci32x4() Op - -[c: 'BinaryenAddVecI32x4'] -pub fn addveci32x4() Op - -[c: 'BinaryenSubVecI32x4'] -pub fn subveci32x4() Op - -[c: 'BinaryenMulVecI32x4'] -pub fn mulveci32x4() Op - -[c: 'BinaryenMinSVecI32x4'] -pub fn minsveci32x4() Op - -[c: 'BinaryenMinUVecI32x4'] -pub fn minuveci32x4() Op - -[c: 'BinaryenMaxSVecI32x4'] -pub fn maxsveci32x4() Op - -[c: 'BinaryenMaxUVecI32x4'] -pub fn maxuveci32x4() Op - -[c: 'BinaryenDotSVecI16x8ToVecI32x4'] -pub fn dotsveci16x8toveci32x4() Op - -[c: 'BinaryenExtMulLowSVecI32x4'] -pub fn extmullowsveci32x4() Op - -[c: 'BinaryenExtMulHighSVecI32x4'] -pub fn extmulhighsveci32x4() Op - -[c: 'BinaryenExtMulLowUVecI32x4'] -pub fn extmullowuveci32x4() Op - -[c: 'BinaryenExtMulHighUVecI32x4'] -pub fn extmulhighuveci32x4() Op - -[c: 'BinaryenAbsVecI64x2'] -pub fn absveci64x2() Op - -[c: 'BinaryenNegVecI64x2'] -pub fn negveci64x2() Op - -[c: 'BinaryenAllTrueVecI64x2'] -pub fn alltrueveci64x2() Op - -[c: 'BinaryenBitmaskVecI64x2'] -pub fn bitmaskveci64x2() Op - -[c: 'BinaryenShlVecI64x2'] -pub fn shlveci64x2() Op - -[c: 'BinaryenShrSVecI64x2'] -pub fn shrsveci64x2() Op - -[c: 'BinaryenShrUVecI64x2'] -pub fn shruveci64x2() Op - -[c: 'BinaryenAddVecI64x2'] -pub fn addveci64x2() Op - -[c: 'BinaryenSubVecI64x2'] -pub fn subveci64x2() Op - -[c: 'BinaryenMulVecI64x2'] -pub fn mulveci64x2() Op - -[c: 'BinaryenExtMulLowSVecI64x2'] -pub fn extmullowsveci64x2() Op - -[c: 'BinaryenExtMulHighSVecI64x2'] -pub fn extmulhighsveci64x2() Op - -[c: 'BinaryenExtMulLowUVecI64x2'] -pub fn extmullowuveci64x2() Op - -[c: 'BinaryenExtMulHighUVecI64x2'] -pub fn extmulhighuveci64x2() Op - -[c: 'BinaryenAbsVecF32x4'] -pub fn absvecf32x4() Op - -[c: 'BinaryenNegVecF32x4'] -pub fn negvecf32x4() Op - -[c: 'BinaryenSqrtVecF32x4'] -pub fn sqrtvecf32x4() Op - -[c: 'BinaryenAddVecF32x4'] -pub fn addvecf32x4() Op - -[c: 'BinaryenSubVecF32x4'] -pub fn subvecf32x4() Op - -[c: 'BinaryenMulVecF32x4'] -pub fn mulvecf32x4() Op - -[c: 'BinaryenDivVecF32x4'] -pub fn divvecf32x4() Op - -[c: 'BinaryenMinVecF32x4'] -pub fn minvecf32x4() Op - -[c: 'BinaryenMaxVecF32x4'] -pub fn maxvecf32x4() Op - -[c: 'BinaryenPMinVecF32x4'] -pub fn pminvecf32x4() Op - -[c: 'BinaryenPMaxVecF32x4'] -pub fn pmaxvecf32x4() Op - -[c: 'BinaryenCeilVecF32x4'] -pub fn ceilvecf32x4() Op - -[c: 'BinaryenFloorVecF32x4'] -pub fn floorvecf32x4() Op - -[c: 'BinaryenTruncVecF32x4'] -pub fn truncvecf32x4() Op - -[c: 'BinaryenNearestVecF32x4'] -pub fn nearestvecf32x4() Op - -[c: 'BinaryenAbsVecF64x2'] -pub fn absvecf64x2() Op - -[c: 'BinaryenNegVecF64x2'] -pub fn negvecf64x2() Op - -[c: 'BinaryenSqrtVecF64x2'] -pub fn sqrtvecf64x2() Op - -[c: 'BinaryenAddVecF64x2'] -pub fn addvecf64x2() Op - -[c: 'BinaryenSubVecF64x2'] -pub fn subvecf64x2() Op - -[c: 'BinaryenMulVecF64x2'] -pub fn mulvecf64x2() Op - -[c: 'BinaryenDivVecF64x2'] -pub fn divvecf64x2() Op - -[c: 'BinaryenMinVecF64x2'] -pub fn minvecf64x2() Op - -[c: 'BinaryenMaxVecF64x2'] -pub fn maxvecf64x2() Op - -[c: 'BinaryenPMinVecF64x2'] -pub fn pminvecf64x2() Op - -[c: 'BinaryenPMaxVecF64x2'] -pub fn pmaxvecf64x2() Op - -[c: 'BinaryenCeilVecF64x2'] -pub fn ceilvecf64x2() Op - -[c: 'BinaryenFloorVecF64x2'] -pub fn floorvecf64x2() Op - -[c: 'BinaryenTruncVecF64x2'] -pub fn truncvecf64x2() Op - -[c: 'BinaryenNearestVecF64x2'] -pub fn nearestvecf64x2() Op - -[c: 'BinaryenExtAddPairwiseSVecI8x16ToI16x8'] -pub fn extaddpairwisesveci8x16toi16x8() Op - -[c: 'BinaryenExtAddPairwiseUVecI8x16ToI16x8'] -pub fn extaddpairwiseuveci8x16toi16x8() Op - -[c: 'BinaryenExtAddPairwiseSVecI16x8ToI32x4'] -pub fn extaddpairwisesveci16x8toi32x4() Op - -[c: 'BinaryenExtAddPairwiseUVecI16x8ToI32x4'] -pub fn extaddpairwiseuveci16x8toi32x4() Op - -[c: 'BinaryenTruncSatSVecF32x4ToVecI32x4'] -pub fn truncsatsvecf32x4toveci32x4() Op - -[c: 'BinaryenTruncSatUVecF32x4ToVecI32x4'] -pub fn truncsatuvecf32x4toveci32x4() Op - -[c: 'BinaryenConvertSVecI32x4ToVecF32x4'] -pub fn convertsveci32x4tovecf32x4() Op - -[c: 'BinaryenConvertUVecI32x4ToVecF32x4'] -pub fn convertuveci32x4tovecf32x4() Op - -[c: 'BinaryenLoad8SplatVec128'] -pub fn load8splatvec128() Op - -[c: 'BinaryenLoad16SplatVec128'] -pub fn load16splatvec128() Op - -[c: 'BinaryenLoad32SplatVec128'] -pub fn load32splatvec128() Op - -[c: 'BinaryenLoad64SplatVec128'] -pub fn load64splatvec128() Op - -[c: 'BinaryenLoad8x8SVec128'] -pub fn load8x8svec128() Op - -[c: 'BinaryenLoad8x8UVec128'] -pub fn load8x8uvec128() Op - -[c: 'BinaryenLoad16x4SVec128'] -pub fn load16x4svec128() Op - -[c: 'BinaryenLoad16x4UVec128'] -pub fn load16x4uvec128() Op - -[c: 'BinaryenLoad32x2SVec128'] -pub fn load32x2svec128() Op - -[c: 'BinaryenLoad32x2UVec128'] -pub fn load32x2uvec128() Op - -[c: 'BinaryenLoad32ZeroVec128'] -pub fn load32zerovec128() Op - -[c: 'BinaryenLoad64ZeroVec128'] -pub fn load64zerovec128() Op - -[c: 'BinaryenLoad8LaneVec128'] -pub fn load8lanevec128() Op - -[c: 'BinaryenLoad16LaneVec128'] -pub fn load16lanevec128() Op - -[c: 'BinaryenLoad32LaneVec128'] -pub fn load32lanevec128() Op - -[c: 'BinaryenLoad64LaneVec128'] -pub fn load64lanevec128() Op - -[c: 'BinaryenStore8LaneVec128'] -pub fn store8lanevec128() Op - -[c: 'BinaryenStore16LaneVec128'] -pub fn store16lanevec128() Op - -[c: 'BinaryenStore32LaneVec128'] -pub fn store32lanevec128() Op - -[c: 'BinaryenStore64LaneVec128'] -pub fn store64lanevec128() Op - -[c: 'BinaryenNarrowSVecI16x8ToVecI8x16'] -pub fn narrowsveci16x8toveci8x16() Op - -[c: 'BinaryenNarrowUVecI16x8ToVecI8x16'] -pub fn narrowuveci16x8toveci8x16() Op - -[c: 'BinaryenNarrowSVecI32x4ToVecI16x8'] -pub fn narrowsveci32x4toveci16x8() Op - -[c: 'BinaryenNarrowUVecI32x4ToVecI16x8'] -pub fn narrowuveci32x4toveci16x8() Op - -[c: 'BinaryenExtendLowSVecI8x16ToVecI16x8'] -pub fn extendlowsveci8x16toveci16x8() Op - -[c: 'BinaryenExtendHighSVecI8x16ToVecI16x8'] -pub fn extendhighsveci8x16toveci16x8() Op - -[c: 'BinaryenExtendLowUVecI8x16ToVecI16x8'] -pub fn extendlowuveci8x16toveci16x8() Op - -[c: 'BinaryenExtendHighUVecI8x16ToVecI16x8'] -pub fn extendhighuveci8x16toveci16x8() Op - -[c: 'BinaryenExtendLowSVecI16x8ToVecI32x4'] -pub fn extendlowsveci16x8toveci32x4() Op - -[c: 'BinaryenExtendHighSVecI16x8ToVecI32x4'] -pub fn extendhighsveci16x8toveci32x4() Op - -[c: 'BinaryenExtendLowUVecI16x8ToVecI32x4'] -pub fn extendlowuveci16x8toveci32x4() Op - -[c: 'BinaryenExtendHighUVecI16x8ToVecI32x4'] -pub fn extendhighuveci16x8toveci32x4() Op - -[c: 'BinaryenExtendLowSVecI32x4ToVecI64x2'] -pub fn extendlowsveci32x4toveci64x2() Op - -[c: 'BinaryenExtendHighSVecI32x4ToVecI64x2'] -pub fn extendhighsveci32x4toveci64x2() Op - -[c: 'BinaryenExtendLowUVecI32x4ToVecI64x2'] -pub fn extendlowuveci32x4toveci64x2() Op - -[c: 'BinaryenExtendHighUVecI32x4ToVecI64x2'] -pub fn extendhighuveci32x4toveci64x2() Op - -[c: 'BinaryenConvertLowSVecI32x4ToVecF64x2'] -pub fn convertlowsveci32x4tovecf64x2() Op - -[c: 'BinaryenConvertLowUVecI32x4ToVecF64x2'] -pub fn convertlowuveci32x4tovecf64x2() Op - -[c: 'BinaryenTruncSatZeroSVecF64x2ToVecI32x4'] -pub fn truncsatzerosvecf64x2toveci32x4() Op - -[c: 'BinaryenTruncSatZeroUVecF64x2ToVecI32x4'] -pub fn truncsatzerouvecf64x2toveci32x4() Op - -[c: 'BinaryenDemoteZeroVecF64x2ToVecF32x4'] -pub fn demotezerovecf64x2tovecf32x4() Op - -[c: 'BinaryenPromoteLowVecF32x4ToVecF64x2'] -pub fn promotelowvecf32x4tovecf64x2() Op - -[c: 'BinaryenSwizzleVecI8x16'] -pub fn swizzleveci8x16() Op - -[c: 'BinaryenRefIsNull'] -pub fn refisnull() Op - -[c: 'BinaryenRefIsFunc'] -pub fn refisfunc() Op - -[c: 'BinaryenRefIsData'] -pub fn refisdata() Op - -[c: 'BinaryenRefIsI31'] -pub fn refisi31() Op - -[c: 'BinaryenRefAsNonNull'] -pub fn refasnonnull() Op - -[c: 'BinaryenRefAsFunc'] -pub fn refasfunc() Op - -[c: 'BinaryenRefAsData'] -pub fn refasdata() Op - -[c: 'BinaryenRefAsI31'] -pub fn refasi31() Op - -[c: 'BinaryenRefAsExternInternalize'] -pub fn refasexterninternalize() Op - -[c: 'BinaryenRefAsExternExternalize'] -pub fn refasexternexternalize() Op - -[c: 'BinaryenBrOnNull'] -pub fn bronnull() Op - -[c: 'BinaryenBrOnNonNull'] -pub fn bronnonnull() Op - -[c: 'BinaryenBrOnCast'] -pub fn broncast() Op - -[c: 'BinaryenBrOnCastFail'] -pub fn broncastfail() Op - -[c: 'BinaryenBrOnFunc'] -pub fn bronfunc() Op - -[c: 'BinaryenBrOnNonFunc'] -pub fn bronnonfunc() Op - -[c: 'BinaryenBrOnData'] -pub fn brondata() Op - -[c: 'BinaryenBrOnNonData'] -pub fn bronnondata() Op - -[c: 'BinaryenBrOnI31'] -pub fn broni31() Op - -[c: 'BinaryenBrOnNonI31'] -pub fn bronnoni31() Op - -[c: 'BinaryenStringNewUTF8'] -pub fn stringnewutf8() Op - -[c: 'BinaryenStringNewWTF8'] -pub fn stringnewwtf8() Op - -[c: 'BinaryenStringNewReplace'] -pub fn stringnewreplace() Op - -[c: 'BinaryenStringNewWTF16'] -pub fn stringnewwtf16() Op - -[c: 'BinaryenStringNewUTF8Array'] -pub fn stringnewutf8array() Op - -[c: 'BinaryenStringNewWTF8Array'] -pub fn stringnewwtf8array() Op - -[c: 'BinaryenStringNewReplaceArray'] -pub fn stringnewreplacearray() Op - -[c: 'BinaryenStringNewWTF16Array'] -pub fn stringnewwtf16array() Op - -[c: 'BinaryenStringMeasureUTF8'] -pub fn stringmeasureutf8() Op - -[c: 'BinaryenStringMeasureWTF8'] -pub fn stringmeasurewtf8() Op - -[c: 'BinaryenStringMeasureWTF16'] -pub fn stringmeasurewtf16() Op - -[c: 'BinaryenStringMeasureIsUSV'] -pub fn stringmeasureisusv() Op - -[c: 'BinaryenStringMeasureWTF16View'] -pub fn stringmeasurewtf16view() Op - -[c: 'BinaryenStringEncodeUTF8'] -pub fn stringencodeutf8() Op - -[c: 'BinaryenStringEncodeWTF8'] -pub fn stringencodewtf8() Op - -[c: 'BinaryenStringEncodeWTF16'] -pub fn stringencodewtf16() Op - -[c: 'BinaryenStringEncodeUTF8Array'] -pub fn stringencodeutf8array() Op - -[c: 'BinaryenStringEncodeWTF8Array'] -pub fn stringencodewtf8array() Op - -[c: 'BinaryenStringEncodeWTF16Array'] -pub fn stringencodewtf16array() Op - -[c: 'BinaryenStringAsWTF8'] -pub fn stringaswtf8() Op - -[c: 'BinaryenStringAsWTF16'] -pub fn stringaswtf16() Op - -[c: 'BinaryenStringAsIter'] -pub fn stringasiter() Op - -[c: 'BinaryenStringIterMoveAdvance'] -pub fn stringitermoveadvance() Op - -[c: 'BinaryenStringIterMoveRewind'] -pub fn stringitermoverewind() Op - -[c: 'BinaryenStringSliceWTF8'] -pub fn stringslicewtf8() Op - -[c: 'BinaryenStringSliceWTF16'] -pub fn stringslicewtf16() Op - -type Expression = voidptr - -[c: 'BinaryenBlock'] -pub fn block(module_ Module, name &i8, children &Expression, numchildren Index, type_ Type) Expression - -[c: 'BinaryenIf'] -pub fn bif(module_ Module, condition Expression, iftrue Expression, iffalse Expression) Expression - -[c: 'BinaryenLoop'] -pub fn loop(module_ Module, in_ &i8, body Expression) Expression - -[c: 'BinaryenBreak'] -pub fn br(module_ Module, name &i8, condition Expression, value Expression) Expression - -[c: 'BinaryenSwitch'] -pub fn switch(module_ Module, names &&u8, numnames Index, defaultname &i8, condition Expression, value Expression) Expression - -[c: 'BinaryenCall'] -pub fn call(module_ Module, target &i8, operands &Expression, numoperands Index, returntype Type) Expression - -[c: 'BinaryenCallIndirect'] -pub fn callindirect(module_ Module, table &i8, target Expression, operands &Expression, numoperands Index, params Type, results Type) Expression - -[c: 'BinaryenReturnCall'] -pub fn returncall(module_ Module, target &i8, operands &Expression, numoperands Index, returntype Type) Expression - -[c: 'BinaryenReturnCallIndirect'] -pub fn returncallindirect(module_ Module, table &i8, target Expression, operands &Expression, numoperands Index, params Type, results Type) Expression - -[c: 'BinaryenLocalGet'] -pub fn localget(module_ Module, index Index, type_ Type) Expression - -[c: 'BinaryenLocalSet'] -pub fn localset(module_ Module, index Index, value Expression) Expression - -[c: 'BinaryenLocalTee'] -pub fn localtee(module_ Module, index Index, value Expression, type_ Type) Expression - -[c: 'BinaryenGlobalGet'] -pub fn globalget(module_ Module, name &i8, type_ Type) Expression - -[c: 'BinaryenGlobalSet'] -pub fn globalset(module_ Module, name &i8, value Expression) Expression - -[c: 'BinaryenLoad'] -pub fn load(module_ Module, bytes u32, signed_ bool, offset u32, align u32, type_ Type, ptr Expression, memoryname &i8) Expression - -[c: 'BinaryenStore'] -pub fn store(module_ Module, bytes u32, offset u32, align u32, ptr Expression, value Expression, type_ Type, memoryname &i8) Expression - -[c: 'BinaryenConst'] -pub fn constant(module_ Module, value Literal) Expression - -[c: 'BinaryenUnary'] -pub fn unary(module_ Module, op Op, value Expression) Expression - -[c: 'BinaryenBinary'] -pub fn binary(module_ Module, op Op, left Expression, right Expression) Expression - -[c: 'BinaryenSelect'] -pub fn bselect(module_ Module, condition Expression, iftrue Expression, iffalse Expression, type_ Type) Expression - -[c: 'BinaryenDrop'] -pub fn drop(module_ Module, value Expression) Expression - -[c: 'BinaryenReturn'] -pub fn ret(module_ Module, value Expression) Expression - -[c: 'BinaryenMemorySize'] -pub fn memorysize(module_ Module, memoryname &i8, memoryis64 bool) Expression - -[c: 'BinaryenMemoryGrow'] -pub fn memorygrow(module_ Module, delta Expression, memoryname &i8, memoryis64 bool) Expression - -[c: 'BinaryenNop'] -pub fn nop(module_ Module) Expression - -[c: 'BinaryenUnreachable'] -pub fn unreachable(module_ Module) Expression - -[c: 'BinaryenAtomicLoad'] -pub fn atomicload(module_ Module, bytes u32, offset u32, type_ Type, ptr Expression, memoryname &i8) Expression - -[c: 'BinaryenAtomicStore'] -pub fn atomicstore(module_ Module, bytes u32, offset u32, ptr Expression, value Expression, type_ Type, memoryname &i8) Expression - -[c: 'BinaryenAtomicRMW'] -pub fn atomicrmw(module_ Module, op Op, bytes Index, offset Index, ptr Expression, value Expression, type_ Type, memoryname &i8) Expression - -[c: 'BinaryenAtomicCmpxchg'] -pub fn atomiccmpxchg(module_ Module, bytes Index, offset Index, ptr Expression, expected Expression, replacement Expression, type_ Type, memoryname &i8) Expression - -[c: 'BinaryenAtomicWait'] -pub fn atomicwait(module_ Module, ptr Expression, expected Expression, timeout Expression, type_ Type, memoryname &i8) Expression - -[c: 'BinaryenAtomicNotify'] -pub fn atomicnotify(module_ Module, ptr Expression, notifycount Expression, memoryname &i8) Expression - -[c: 'BinaryenAtomicFence'] -pub fn atomicfence(module_ Module) Expression - -[c: 'BinaryenSIMDExtract'] -pub fn simdextract(module_ Module, op Op, vec Expression, index u8) Expression - -[c: 'BinaryenSIMDReplace'] -pub fn simdreplace(module_ Module, op Op, vec Expression, index u8, value Expression) Expression - -[c: 'BinaryenSIMDShuffle'] -pub fn simdshuffle(module_ Module, left Expression, right Expression, mask &u8) Expression - -[c: 'BinaryenSIMDTernary'] -pub fn simdternary(module_ Module, op Op, a Expression, b Expression, c Expression) Expression - -[c: 'BinaryenSIMDShift'] -pub fn simdshift(module_ Module, op Op, vec Expression, shift Expression) Expression - -[c: 'BinaryenSIMDLoad'] -pub fn simdload(module_ Module, op Op, offset u32, align u32, ptr Expression, name &i8) Expression - -[c: 'BinaryenSIMDLoadStoreLane'] -pub fn simdloadstorelane(module_ Module, op Op, offset u32, align u32, index u8, ptr Expression, vec Expression, memoryname &i8) Expression - -[c: 'BinaryenMemoryInit'] -pub fn memoryinit(module_ Module, segment u32, dest Expression, offset Expression, size Expression, memoryname &i8) Expression - -[c: 'BinaryenDataDrop'] -pub fn datadrop(module_ Module, segment u32) Expression - -[c: 'BinaryenMemoryCopy'] -pub fn memorycopy(module_ Module, dest Expression, source Expression, size Expression, destmemory &i8, sourcememory &i8) Expression - -[c: 'BinaryenMemoryFill'] -pub fn memoryfill(module_ Module, dest Expression, value Expression, size Expression, memoryname &i8) Expression - -[c: 'BinaryenRefNull'] -pub fn refnull(module_ Module, type_ Type) Expression - -[c: 'BinaryenRefIs'] -pub fn refis(module_ Module, op Op, value Expression) Expression - -[c: 'BinaryenRefAs'] -pub fn refas(module_ Module, op Op, value Expression) Expression - -[c: 'BinaryenRefFunc'] -pub fn reffunc(module_ Module, func &i8, type_ Type) Expression - -[c: 'BinaryenRefEq'] -pub fn refeq(module_ Module, left Expression, right Expression) Expression - -[c: 'BinaryenTableGet'] -pub fn tableget(module_ Module, name &i8, index Expression, type_ Type) Expression - -[c: 'BinaryenTableSet'] -pub fn tableset(module_ Module, name &i8, index Expression, value Expression) Expression - -[c: 'BinaryenTableSize'] -pub fn tablesize(module_ Module, name &i8) Expression - -[c: 'BinaryenTableGrow'] -pub fn tablegrow(module_ Module, name &i8, value Expression, delta Expression) Expression - -[c: 'BinaryenTry'] -pub fn try(module_ Module, name &i8, body Expression, catchtags &&u8, numcatchtags Index, catchbodies &Expression, numcatchbodies Index, delegatetarget &i8) Expression - -[c: 'BinaryenThrow'] -pub fn throw(module_ Module, tag &i8, operands &Expression, numoperands Index) Expression - -[c: 'BinaryenRethrow'] -pub fn rethrow(module_ Module, target &i8) Expression - -[c: 'BinaryenTupleMake'] -pub fn tuplemake(module_ Module, operands &Expression, numoperands Index) Expression - -[c: 'BinaryenTupleExtract'] -pub fn tupleextract(module_ Module, tuple Expression, index Index) Expression - -[c: 'BinaryenPop'] -pub fn pop(module_ Module, type_ Type) Expression - -[c: 'BinaryenI31New'] -pub fn i31new(module_ Module, value Expression) Expression - -[c: 'BinaryenI31Get'] -pub fn i31get(module_ Module, i31 Expression, signed_ bool) Expression - -[c: 'BinaryenCallRef'] -pub fn callref(module_ Module, target Expression, operands &Expression, numoperands Index, type_ Type, isreturn bool) Expression - -[c: 'BinaryenRefTest'] -pub fn reftest(module_ Module, ref Expression, intendedtype HeapType) Expression - -[c: 'BinaryenRefCast'] -pub fn refcast(module_ Module, ref Expression, intendedtype HeapType) Expression - -[c: 'BinaryenBrOn'] -pub fn bron(module_ Module, op Op, name &i8, ref Expression, intendedtype HeapType) Expression - -[c: 'BinaryenStructNew'] -pub fn structnew(module_ Module, operands &Expression, numoperands Index, type_ HeapType) Expression - -[c: 'BinaryenStructGet'] -pub fn structget(module_ Module, index Index, ref Expression, type_ Type, signed_ bool) Expression - -[c: 'BinaryenStructSet'] -pub fn structset(module_ Module, index Index, ref Expression, value Expression) Expression - -[c: 'BinaryenArrayNew'] -pub fn arraynew(module_ Module, type_ HeapType, size Expression, init Expression) Expression - -[c: 'BinaryenArrayInit'] -pub fn arrayinit(module_ Module, type_ HeapType, values &Expression, numvalues Index) Expression - -[c: 'BinaryenArrayGet'] -pub fn arrayget(module_ Module, ref Expression, index Expression, type_ Type, signed_ bool) Expression - -[c: 'BinaryenArraySet'] -pub fn arrayset(module_ Module, ref Expression, index Expression, value Expression) Expression - -[c: 'BinaryenArrayLen'] -pub fn arraylen(module_ Module, ref Expression) Expression - -[c: 'BinaryenArrayCopy'] -pub fn arraycopy(module_ Module, destref Expression, destindex Expression, srcref Expression, srcindex Expression, length Expression) Expression - -[c: 'BinaryenStringNew'] -pub fn stringnew(module_ Module, op Op, ptr Expression, length Expression, start Expression, end Expression) Expression - -[c: 'BinaryenStringConst'] -pub fn stringconst(module_ Module, name &i8) Expression - -[c: 'BinaryenStringMeasure'] -pub fn stringmeasure(module_ Module, op Op, ref Expression) Expression - -[c: 'BinaryenStringEncode'] -pub fn stringencode(module_ Module, op Op, ref Expression, ptr Expression, start Expression) Expression - -[c: 'BinaryenStringConcat'] -pub fn stringconcat(module_ Module, left Expression, right Expression) Expression - -[c: 'BinaryenStringEq'] -pub fn stringeq(module_ Module, left Expression, right Expression) Expression - -[c: 'BinaryenStringAs'] -pub fn stringas(module_ Module, op Op, ref Expression) Expression - -[c: 'BinaryenStringWTF8Advance'] -pub fn stringwtf8advance(module_ Module, ref Expression, pos Expression, bytes Expression) Expression - -[c: 'BinaryenStringWTF16Get'] -pub fn stringwtf16get(module_ Module, ref Expression, pos Expression) Expression - -[c: 'BinaryenStringIterNext'] -pub fn stringiternext(module_ Module, ref Expression) Expression - -[c: 'BinaryenStringIterMove'] -pub fn stringitermove(module_ Module, op Op, ref Expression, num Expression) Expression - -[c: 'BinaryenStringSliceWTF'] -pub fn stringslicewtf(module_ Module, op Op, ref Expression, start Expression, end Expression) Expression - -[c: 'BinaryenStringSliceIter'] -pub fn stringsliceiter(module_ Module, ref Expression, num Expression) Expression - -[c: 'BinaryenExpressionGetId'] -pub fn expressiongetid(expr Expression) ExpressionId - -[c: 'BinaryenExpressionGetType'] -pub fn expressiongettype(expr Expression) Type - -[c: 'BinaryenExpressionSetType'] -pub fn expressionsettype(expr Expression, type_ Type) - -[c: 'BinaryenExpressionPrint'] -pub fn expressionprint(expr Expression) - -[c: 'BinaryenExpressionFinalize'] -pub fn expressionfinalize(expr Expression) - -[c: 'BinaryenExpressionCopy'] -pub fn expressioncopy(expr Expression, module_ Module) Expression - -[c: 'BinaryenBlockGetName'] -pub fn blockgetname(expr Expression) &i8 - -[c: 'BinaryenBlockSetName'] -pub fn blocksetname(expr Expression, name &i8) - -[c: 'BinaryenBlockGetNumChildren'] -pub fn blockgetnumchildren(expr Expression) Index - -[c: 'BinaryenBlockGetChildAt'] -pub fn blockgetchildat(expr Expression, index Index) Expression - -[c: 'BinaryenBlockSetChildAt'] -pub fn blocksetchildat(expr Expression, index Index, childexpr Expression) - -[c: 'BinaryenBlockAppendChild'] -pub fn blockappendchild(expr Expression, childexpr Expression) Index - -[c: 'BinaryenBlockInsertChildAt'] -pub fn blockinsertchildat(expr Expression, index Index, childexpr Expression) - -[c: 'BinaryenBlockRemoveChildAt'] -pub fn blockremovechildat(expr Expression, index Index) Expression - -[c: 'BinaryenIfGetCondition'] -pub fn ifgetcondition(expr Expression) Expression - -[c: 'BinaryenIfSetCondition'] -pub fn ifsetcondition(expr Expression, condexpr Expression) - -[c: 'BinaryenIfGetIfTrue'] -pub fn ifgetiftrue(expr Expression) Expression - -[c: 'BinaryenIfSetIfTrue'] -pub fn ifsetiftrue(expr Expression, iftrueexpr Expression) - -[c: 'BinaryenIfGetIfFalse'] -pub fn ifgetiffalse(expr Expression) Expression - -[c: 'BinaryenIfSetIfFalse'] -pub fn ifsetiffalse(expr Expression, iffalseexpr Expression) - -[c: 'BinaryenLoopGetName'] -pub fn loopgetname(expr Expression) &i8 - -[c: 'BinaryenLoopSetName'] -pub fn loopsetname(expr Expression, name &i8) - -[c: 'BinaryenLoopGetBody'] -pub fn loopgetbody(expr Expression) Expression - -[c: 'BinaryenLoopSetBody'] -pub fn loopsetbody(expr Expression, bodyexpr Expression) - -[c: 'BinaryenBreakGetName'] -pub fn breakgetname(expr Expression) &i8 - -[c: 'BinaryenBreakSetName'] -pub fn breaksetname(expr Expression, name &i8) - -[c: 'BinaryenBreakGetCondition'] -pub fn breakgetcondition(expr Expression) Expression - -[c: 'BinaryenBreakSetCondition'] -pub fn breaksetcondition(expr Expression, condexpr Expression) - -[c: 'BinaryenBreakGetValue'] -pub fn breakgetvalue(expr Expression) Expression - -[c: 'BinaryenBreakSetValue'] -pub fn breaksetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenSwitchGetNumNames'] -pub fn switchgetnumnames(expr Expression) Index - -[c: 'BinaryenSwitchGetNameAt'] -pub fn switchgetnameat(expr Expression, index Index) &i8 - -[c: 'BinaryenSwitchSetNameAt'] -pub fn switchsetnameat(expr Expression, index Index, name &i8) - -[c: 'BinaryenSwitchAppendName'] -pub fn switchappendname(expr Expression, name &i8) Index - -[c: 'BinaryenSwitchInsertNameAt'] -pub fn switchinsertnameat(expr Expression, index Index, name &i8) - -[c: 'BinaryenSwitchRemoveNameAt'] -pub fn switchremovenameat(expr Expression, index Index) &i8 - -[c: 'BinaryenSwitchGetDefaultName'] -pub fn switchgetdefaultname(expr Expression) &i8 - -[c: 'BinaryenSwitchSetDefaultName'] -pub fn switchsetdefaultname(expr Expression, name &i8) - -[c: 'BinaryenSwitchGetCondition'] -pub fn switchgetcondition(expr Expression) Expression - -[c: 'BinaryenSwitchSetCondition'] -pub fn switchsetcondition(expr Expression, condexpr Expression) - -[c: 'BinaryenSwitchGetValue'] -pub fn switchgetvalue(expr Expression) Expression - -[c: 'BinaryenSwitchSetValue'] -pub fn switchsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenCallGetTarget'] -pub fn callgettarget(expr Expression) &i8 - -[c: 'BinaryenCallSetTarget'] -pub fn callsettarget(expr Expression, target &i8) - -[c: 'BinaryenCallGetNumOperands'] -pub fn callgetnumoperands(expr Expression) Index - -[c: 'BinaryenCallGetOperandAt'] -pub fn callgetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallSetOperandAt'] -pub fn callsetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallAppendOperand'] -pub fn callappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenCallInsertOperandAt'] -pub fn callinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallRemoveOperandAt'] -pub fn callremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallIsReturn'] -pub fn callisreturn(expr Expression) bool - -[c: 'BinaryenCallSetReturn'] -pub fn callsetreturn(expr Expression, isreturn bool) - -[c: 'BinaryenCallIndirectGetTarget'] -pub fn callindirectgettarget(expr Expression) Expression - -[c: 'BinaryenCallIndirectSetTarget'] -pub fn callindirectsettarget(expr Expression, targetexpr Expression) - -[c: 'BinaryenCallIndirectGetTable'] -pub fn callindirectgettable(expr Expression) &i8 - -[c: 'BinaryenCallIndirectSetTable'] -pub fn callindirectsettable(expr Expression, table &i8) - -[c: 'BinaryenCallIndirectGetNumOperands'] -pub fn callindirectgetnumoperands(expr Expression) Index - -[c: 'BinaryenCallIndirectGetOperandAt'] -pub fn callindirectgetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallIndirectSetOperandAt'] -pub fn callindirectsetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallIndirectAppendOperand'] -pub fn callindirectappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenCallIndirectInsertOperandAt'] -pub fn callindirectinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallIndirectRemoveOperandAt'] -pub fn callindirectremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallIndirectIsReturn'] -pub fn callindirectisreturn(expr Expression) bool - -[c: 'BinaryenCallIndirectSetReturn'] -pub fn callindirectsetreturn(expr Expression, isreturn bool) - -[c: 'BinaryenCallIndirectGetParams'] -pub fn callindirectgetparams(expr Expression) Type - -[c: 'BinaryenCallIndirectSetParams'] -pub fn callindirectsetparams(expr Expression, params Type) - -[c: 'BinaryenCallIndirectGetResults'] -pub fn callindirectgetresults(expr Expression) Type - -[c: 'BinaryenCallIndirectSetResults'] -pub fn callindirectsetresults(expr Expression, params Type) - -[c: 'BinaryenLocalGetGetIndex'] -pub fn localgetgetindex(expr Expression) Index - -[c: 'BinaryenLocalGetSetIndex'] -pub fn localgetsetindex(expr Expression, index Index) - -[c: 'BinaryenLocalSetIsTee'] -pub fn localsetistee(expr Expression) bool - -[c: 'BinaryenLocalSetGetIndex'] -pub fn localsetgetindex(expr Expression) Index - -[c: 'BinaryenLocalSetSetIndex'] -pub fn localsetsetindex(expr Expression, index Index) - -[c: 'BinaryenLocalSetGetValue'] -pub fn localsetgetvalue(expr Expression) Expression - -[c: 'BinaryenLocalSetSetValue'] -pub fn localsetsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenGlobalGetGetName'] -pub fn globalgetgetname(expr Expression) &i8 - -[c: 'BinaryenGlobalGetSetName'] -pub fn globalgetsetname(expr Expression, name &i8) - -[c: 'BinaryenGlobalSetGetName'] -pub fn globalsetgetname(expr Expression) &i8 - -[c: 'BinaryenGlobalSetSetName'] -pub fn globalsetsetname(expr Expression, name &i8) - -[c: 'BinaryenGlobalSetGetValue'] -pub fn globalsetgetvalue(expr Expression) Expression - -[c: 'BinaryenGlobalSetSetValue'] -pub fn globalsetsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenTableGetGetTable'] -pub fn tablegetgettable(expr Expression) &i8 - -[c: 'BinaryenTableGetSetTable'] -pub fn tablegetsettable(expr Expression, table &i8) - -[c: 'BinaryenTableGetGetIndex'] -pub fn tablegetgetindex(expr Expression) Expression - -[c: 'BinaryenTableGetSetIndex'] -pub fn tablegetsetindex(expr Expression, indexexpr Expression) - -[c: 'BinaryenTableSetGetTable'] -pub fn tablesetgettable(expr Expression) &i8 - -[c: 'BinaryenTableSetSetTable'] -pub fn tablesetsettable(expr Expression, table &i8) - -[c: 'BinaryenTableSetGetIndex'] -pub fn tablesetgetindex(expr Expression) Expression - -[c: 'BinaryenTableSetSetIndex'] -pub fn tablesetsetindex(expr Expression, indexexpr Expression) - -[c: 'BinaryenTableSetGetValue'] -pub fn tablesetgetvalue(expr Expression) Expression - -[c: 'BinaryenTableSetSetValue'] -pub fn tablesetsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenTableSizeGetTable'] -pub fn tablesizegettable(expr Expression) &i8 - -[c: 'BinaryenTableSizeSetTable'] -pub fn tablesizesettable(expr Expression, table &i8) - -[c: 'BinaryenTableGrowGetTable'] -pub fn tablegrowgettable(expr Expression) &i8 - -[c: 'BinaryenTableGrowSetTable'] -pub fn tablegrowsettable(expr Expression, table &i8) - -[c: 'BinaryenTableGrowGetValue'] -pub fn tablegrowgetvalue(expr Expression) Expression - -[c: 'BinaryenTableGrowSetValue'] -pub fn tablegrowsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenTableGrowGetDelta'] -pub fn tablegrowgetdelta(expr Expression) Expression - -[c: 'BinaryenTableGrowSetDelta'] -pub fn tablegrowsetdelta(expr Expression, deltaexpr Expression) - -[c: 'BinaryenMemoryGrowGetDelta'] -pub fn memorygrowgetdelta(expr Expression) Expression - -[c: 'BinaryenMemoryGrowSetDelta'] -pub fn memorygrowsetdelta(expr Expression, deltaexpr Expression) - -[c: 'BinaryenLoadIsAtomic'] -pub fn loadisatomic(expr Expression) bool - -[c: 'BinaryenLoadSetAtomic'] -pub fn loadsetatomic(expr Expression, isatomic bool) - -[c: 'BinaryenLoadIsSigned'] -pub fn loadissigned(expr Expression) bool - -[c: 'BinaryenLoadSetSigned'] -pub fn loadsetsigned(expr Expression, issigned bool) - -[c: 'BinaryenLoadGetOffset'] -pub fn loadgetoffset(expr Expression) u32 - -[c: 'BinaryenLoadSetOffset'] -pub fn loadsetoffset(expr Expression, offset u32) - -[c: 'BinaryenLoadGetBytes'] -pub fn loadgetbytes(expr Expression) u32 - -[c: 'BinaryenLoadSetBytes'] -pub fn loadsetbytes(expr Expression, bytes u32) - -[c: 'BinaryenLoadGetAlign'] -pub fn loadgetalign(expr Expression) u32 - -[c: 'BinaryenLoadSetAlign'] -pub fn loadsetalign(expr Expression, align u32) - -[c: 'BinaryenLoadGetPtr'] -pub fn loadgetptr(expr Expression) Expression - -[c: 'BinaryenLoadSetPtr'] -pub fn loadsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenStoreIsAtomic'] -pub fn storeisatomic(expr Expression) bool - -[c: 'BinaryenStoreSetAtomic'] -pub fn storesetatomic(expr Expression, isatomic bool) - -[c: 'BinaryenStoreGetBytes'] -pub fn storegetbytes(expr Expression) u32 - -[c: 'BinaryenStoreSetBytes'] -pub fn storesetbytes(expr Expression, bytes u32) - -[c: 'BinaryenStoreGetOffset'] -pub fn storegetoffset(expr Expression) u32 - -[c: 'BinaryenStoreSetOffset'] -pub fn storesetoffset(expr Expression, offset u32) - -[c: 'BinaryenStoreGetAlign'] -pub fn storegetalign(expr Expression) u32 - -[c: 'BinaryenStoreSetAlign'] -pub fn storesetalign(expr Expression, align u32) - -[c: 'BinaryenStoreGetPtr'] -pub fn storegetptr(expr Expression) Expression - -[c: 'BinaryenStoreSetPtr'] -pub fn storesetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenStoreGetValue'] -pub fn storegetvalue(expr Expression) Expression - -[c: 'BinaryenStoreSetValue'] -pub fn storesetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenStoreGetValueType'] -pub fn storegetvaluetype(expr Expression) Type - -[c: 'BinaryenStoreSetValueType'] -pub fn storesetvaluetype(expr Expression, valuetype Type) - -[c: 'BinaryenConstGetValueI32'] -pub fn constgetvaluei32(expr Expression) int - -[c: 'BinaryenConstSetValueI32'] -pub fn constsetvaluei32(expr Expression, value int) - -[c: 'BinaryenConstGetValueI64'] -pub fn constgetvaluei64(expr Expression) i64 - -[c: 'BinaryenConstSetValueI64'] -pub fn constsetvaluei64(expr Expression, value i64) - -[c: 'BinaryenConstGetValueI64Low'] -pub fn constgetvaluei64low(expr Expression) int - -[c: 'BinaryenConstSetValueI64Low'] -pub fn constsetvaluei64low(expr Expression, valuelow int) - -[c: 'BinaryenConstGetValueI64High'] -pub fn constgetvaluei64high(expr Expression) int - -[c: 'BinaryenConstSetValueI64High'] -pub fn constsetvaluei64high(expr Expression, valuehigh int) - -[c: 'BinaryenConstGetValueF32'] -pub fn constgetvaluef32(expr Expression) f32 - -[c: 'BinaryenConstSetValueF32'] -pub fn constsetvaluef32(expr Expression, value f32) - -[c: 'BinaryenConstGetValueF64'] -pub fn constgetvaluef64(expr Expression) f64 - -[c: 'BinaryenConstSetValueF64'] -pub fn constsetvaluef64(expr Expression, value f64) - -[c: 'BinaryenConstGetValueV128'] -pub fn constgetvaluev128(expr Expression, out &u8) - -[c: 'BinaryenConstSetValueV128'] -pub fn constsetvaluev128(expr Expression, value &u8) - -[c: 'BinaryenUnaryGetOp'] -pub fn unarygetop(expr Expression) Op - -[c: 'BinaryenUnarySetOp'] -pub fn unarysetop(expr Expression, op Op) - -[c: 'BinaryenUnaryGetValue'] -pub fn unarygetvalue(expr Expression) Expression - -[c: 'BinaryenUnarySetValue'] -pub fn unarysetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenBinaryGetOp'] -pub fn binarygetop(expr Expression) Op - -[c: 'BinaryenBinarySetOp'] -pub fn binarysetop(expr Expression, op Op) - -[c: 'BinaryenBinaryGetLeft'] -pub fn binarygetleft(expr Expression) Expression - -[c: 'BinaryenBinarySetLeft'] -pub fn binarysetleft(expr Expression, leftexpr Expression) - -[c: 'BinaryenBinaryGetRight'] -pub fn binarygetright(expr Expression) Expression - -[c: 'BinaryenBinarySetRight'] -pub fn binarysetright(expr Expression, rightexpr Expression) - -[c: 'BinaryenSelectGetIfTrue'] -pub fn selectgetiftrue(expr Expression) Expression - -[c: 'BinaryenSelectSetIfTrue'] -pub fn selectsetiftrue(expr Expression, iftrueexpr Expression) - -[c: 'BinaryenSelectGetIfFalse'] -pub fn selectgetiffalse(expr Expression) Expression - -[c: 'BinaryenSelectSetIfFalse'] -pub fn selectsetiffalse(expr Expression, iffalseexpr Expression) - -[c: 'BinaryenSelectGetCondition'] -pub fn selectgetcondition(expr Expression) Expression - -[c: 'BinaryenSelectSetCondition'] -pub fn selectsetcondition(expr Expression, condexpr Expression) - -[c: 'BinaryenDropGetValue'] -pub fn dropgetvalue(expr Expression) Expression - -[c: 'BinaryenDropSetValue'] -pub fn dropsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenReturnGetValue'] -pub fn returngetvalue(expr Expression) Expression - -[c: 'BinaryenReturnSetValue'] -pub fn returnsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenAtomicRMWGetOp'] -pub fn atomicrmwgetop(expr Expression) Op - -[c: 'BinaryenAtomicRMWSetOp'] -pub fn atomicrmwsetop(expr Expression, op Op) - -[c: 'BinaryenAtomicRMWGetBytes'] -pub fn atomicrmwgetbytes(expr Expression) u32 - -[c: 'BinaryenAtomicRMWSetBytes'] -pub fn atomicrmwsetbytes(expr Expression, bytes u32) - -[c: 'BinaryenAtomicRMWGetOffset'] -pub fn atomicrmwgetoffset(expr Expression) u32 - -[c: 'BinaryenAtomicRMWSetOffset'] -pub fn atomicrmwsetoffset(expr Expression, offset u32) - -[c: 'BinaryenAtomicRMWGetPtr'] -pub fn atomicrmwgetptr(expr Expression) Expression - -[c: 'BinaryenAtomicRMWSetPtr'] -pub fn atomicrmwsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenAtomicRMWGetValue'] -pub fn atomicrmwgetvalue(expr Expression) Expression - -[c: 'BinaryenAtomicRMWSetValue'] -pub fn atomicrmwsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenAtomicCmpxchgGetBytes'] -pub fn atomiccmpxchggetbytes(expr Expression) u32 - -[c: 'BinaryenAtomicCmpxchgSetBytes'] -pub fn atomiccmpxchgsetbytes(expr Expression, bytes u32) - -[c: 'BinaryenAtomicCmpxchgGetOffset'] -pub fn atomiccmpxchggetoffset(expr Expression) u32 - -[c: 'BinaryenAtomicCmpxchgSetOffset'] -pub fn atomiccmpxchgsetoffset(expr Expression, offset u32) - -[c: 'BinaryenAtomicCmpxchgGetPtr'] -pub fn atomiccmpxchggetptr(expr Expression) Expression - -[c: 'BinaryenAtomicCmpxchgSetPtr'] -pub fn atomiccmpxchgsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenAtomicCmpxchgGetExpected'] -pub fn atomiccmpxchggetexpected(expr Expression) Expression - -[c: 'BinaryenAtomicCmpxchgSetExpected'] -pub fn atomiccmpxchgsetexpected(expr Expression, expectedexpr Expression) - -[c: 'BinaryenAtomicCmpxchgGetReplacement'] -pub fn atomiccmpxchggetreplacement(expr Expression) Expression - -[c: 'BinaryenAtomicCmpxchgSetReplacement'] -pub fn atomiccmpxchgsetreplacement(expr Expression, replacementexpr Expression) - -[c: 'BinaryenAtomicWaitGetPtr'] -pub fn atomicwaitgetptr(expr Expression) Expression - -[c: 'BinaryenAtomicWaitSetPtr'] -pub fn atomicwaitsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenAtomicWaitGetExpected'] -pub fn atomicwaitgetexpected(expr Expression) Expression - -[c: 'BinaryenAtomicWaitSetExpected'] -pub fn atomicwaitsetexpected(expr Expression, expectedexpr Expression) - -[c: 'BinaryenAtomicWaitGetTimeout'] -pub fn atomicwaitgettimeout(expr Expression) Expression - -[c: 'BinaryenAtomicWaitSetTimeout'] -pub fn atomicwaitsettimeout(expr Expression, timeoutexpr Expression) - -[c: 'BinaryenAtomicWaitGetExpectedType'] -pub fn atomicwaitgetexpectedtype(expr Expression) Type - -[c: 'BinaryenAtomicWaitSetExpectedType'] -pub fn atomicwaitsetexpectedtype(expr Expression, expectedtype Type) - -[c: 'BinaryenAtomicNotifyGetPtr'] -pub fn atomicnotifygetptr(expr Expression) Expression - -[c: 'BinaryenAtomicNotifySetPtr'] -pub fn atomicnotifysetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenAtomicNotifyGetNotifyCount'] -pub fn atomicnotifygetnotifycount(expr Expression) Expression - -[c: 'BinaryenAtomicNotifySetNotifyCount'] -pub fn atomicnotifysetnotifycount(expr Expression, notifycountexpr Expression) - -[c: 'BinaryenAtomicFenceGetOrder'] -pub fn atomicfencegetorder(expr Expression) u8 - -[c: 'BinaryenAtomicFenceSetOrder'] -pub fn atomicfencesetorder(expr Expression, order u8) - -[c: 'BinaryenSIMDExtractGetOp'] -pub fn simdextractgetop(expr Expression) Op - -[c: 'BinaryenSIMDExtractSetOp'] -pub fn simdextractsetop(expr Expression, op Op) - -[c: 'BinaryenSIMDExtractGetVec'] -pub fn simdextractgetvec(expr Expression) Expression - -[c: 'BinaryenSIMDExtractSetVec'] -pub fn simdextractsetvec(expr Expression, vecexpr Expression) - -[c: 'BinaryenSIMDExtractGetIndex'] -pub fn simdextractgetindex(expr Expression) u8 - -[c: 'BinaryenSIMDExtractSetIndex'] -pub fn simdextractsetindex(expr Expression, index u8) - -[c: 'BinaryenSIMDReplaceGetOp'] -pub fn simdreplacegetop(expr Expression) Op - -[c: 'BinaryenSIMDReplaceSetOp'] -pub fn simdreplacesetop(expr Expression, op Op) - -[c: 'BinaryenSIMDReplaceGetVec'] -pub fn simdreplacegetvec(expr Expression) Expression - -[c: 'BinaryenSIMDReplaceSetVec'] -pub fn simdreplacesetvec(expr Expression, vecexpr Expression) - -[c: 'BinaryenSIMDReplaceGetIndex'] -pub fn simdreplacegetindex(expr Expression) u8 - -[c: 'BinaryenSIMDReplaceSetIndex'] -pub fn simdreplacesetindex(expr Expression, index u8) - -[c: 'BinaryenSIMDReplaceGetValue'] -pub fn simdreplacegetvalue(expr Expression) Expression - -[c: 'BinaryenSIMDReplaceSetValue'] -pub fn simdreplacesetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenSIMDShuffleGetLeft'] -pub fn simdshufflegetleft(expr Expression) Expression - -[c: 'BinaryenSIMDShuffleSetLeft'] -pub fn simdshufflesetleft(expr Expression, leftexpr Expression) - -[c: 'BinaryenSIMDShuffleGetRight'] -pub fn simdshufflegetright(expr Expression) Expression - -[c: 'BinaryenSIMDShuffleSetRight'] -pub fn simdshufflesetright(expr Expression, rightexpr Expression) - -[c: 'BinaryenSIMDShuffleGetMask'] -pub fn simdshufflegetmask(expr Expression, mask &u8) - -[c: 'BinaryenSIMDShuffleSetMask'] -pub fn simdshufflesetmask(expr Expression, mask &u8) - -[c: 'BinaryenSIMDTernaryGetOp'] -pub fn simdternarygetop(expr Expression) Op - -[c: 'BinaryenSIMDTernarySetOp'] -pub fn simdternarysetop(expr Expression, op Op) - -[c: 'BinaryenSIMDTernaryGetA'] -pub fn simdternarygeta(expr Expression) Expression - -[c: 'BinaryenSIMDTernarySetA'] -pub fn simdternaryseta(expr Expression, aexpr Expression) - -[c: 'BinaryenSIMDTernaryGetB'] -pub fn simdternarygetb(expr Expression) Expression - -[c: 'BinaryenSIMDTernarySetB'] -pub fn simdternarysetb(expr Expression, bexpr Expression) - -[c: 'BinaryenSIMDTernaryGetC'] -pub fn simdternarygetc(expr Expression) Expression - -[c: 'BinaryenSIMDTernarySetC'] -pub fn simdternarysetc(expr Expression, cexpr Expression) - -[c: 'BinaryenSIMDShiftGetOp'] -pub fn simdshiftgetop(expr Expression) Op - -[c: 'BinaryenSIMDShiftSetOp'] -pub fn simdshiftsetop(expr Expression, op Op) - -[c: 'BinaryenSIMDShiftGetVec'] -pub fn simdshiftgetvec(expr Expression) Expression - -[c: 'BinaryenSIMDShiftSetVec'] -pub fn simdshiftsetvec(expr Expression, vecexpr Expression) - -[c: 'BinaryenSIMDShiftGetShift'] -pub fn simdshiftgetshift(expr Expression) Expression - -[c: 'BinaryenSIMDShiftSetShift'] -pub fn simdshiftsetshift(expr Expression, shiftexpr Expression) - -[c: 'BinaryenSIMDLoadGetOp'] -pub fn simdloadgetop(expr Expression) Op - -[c: 'BinaryenSIMDLoadSetOp'] -pub fn simdloadsetop(expr Expression, op Op) - -[c: 'BinaryenSIMDLoadGetOffset'] -pub fn simdloadgetoffset(expr Expression) u32 - -[c: 'BinaryenSIMDLoadSetOffset'] -pub fn simdloadsetoffset(expr Expression, offset u32) - -[c: 'BinaryenSIMDLoadGetAlign'] -pub fn simdloadgetalign(expr Expression) u32 - -[c: 'BinaryenSIMDLoadSetAlign'] -pub fn simdloadsetalign(expr Expression, align u32) - -[c: 'BinaryenSIMDLoadGetPtr'] -pub fn simdloadgetptr(expr Expression) Expression - -[c: 'BinaryenSIMDLoadSetPtr'] -pub fn simdloadsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenSIMDLoadStoreLaneGetOp'] -pub fn simdloadstorelanegetop(expr Expression) Op - -[c: 'BinaryenSIMDLoadStoreLaneSetOp'] -pub fn simdloadstorelanesetop(expr Expression, op Op) - -[c: 'BinaryenSIMDLoadStoreLaneGetOffset'] -pub fn simdloadstorelanegetoffset(expr Expression) u32 - -[c: 'BinaryenSIMDLoadStoreLaneSetOffset'] -pub fn simdloadstorelanesetoffset(expr Expression, offset u32) - -[c: 'BinaryenSIMDLoadStoreLaneGetAlign'] -pub fn simdloadstorelanegetalign(expr Expression) u32 - -[c: 'BinaryenSIMDLoadStoreLaneSetAlign'] -pub fn simdloadstorelanesetalign(expr Expression, align u32) - -[c: 'BinaryenSIMDLoadStoreLaneGetIndex'] -pub fn simdloadstorelanegetindex(expr Expression) u8 - -[c: 'BinaryenSIMDLoadStoreLaneSetIndex'] -pub fn simdloadstorelanesetindex(expr Expression, index u8) - -[c: 'BinaryenSIMDLoadStoreLaneGetPtr'] -pub fn simdloadstorelanegetptr(expr Expression) Expression - -[c: 'BinaryenSIMDLoadStoreLaneSetPtr'] -pub fn simdloadstorelanesetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenSIMDLoadStoreLaneGetVec'] -pub fn simdloadstorelanegetvec(expr Expression) Expression - -[c: 'BinaryenSIMDLoadStoreLaneSetVec'] -pub fn simdloadstorelanesetvec(expr Expression, vecexpr Expression) - -[c: 'BinaryenSIMDLoadStoreLaneIsStore'] -pub fn simdloadstorelaneisstore(expr Expression) bool - -[c: 'BinaryenMemoryInitGetSegment'] -pub fn memoryinitgetsegment(expr Expression) u32 - -[c: 'BinaryenMemoryInitSetSegment'] -pub fn memoryinitsetsegment(expr Expression, segmentindex u32) - -[c: 'BinaryenMemoryInitGetDest'] -pub fn memoryinitgetdest(expr Expression) Expression - -[c: 'BinaryenMemoryInitSetDest'] -pub fn memoryinitsetdest(expr Expression, destexpr Expression) - -[c: 'BinaryenMemoryInitGetOffset'] -pub fn memoryinitgetoffset(expr Expression) Expression - -[c: 'BinaryenMemoryInitSetOffset'] -pub fn memoryinitsetoffset(expr Expression, offsetexpr Expression) - -[c: 'BinaryenMemoryInitGetSize'] -pub fn memoryinitgetsize(expr Expression) Expression - -[c: 'BinaryenMemoryInitSetSize'] -pub fn memoryinitsetsize(expr Expression, sizeexpr Expression) - -[c: 'BinaryenDataDropGetSegment'] -pub fn datadropgetsegment(expr Expression) u32 - -[c: 'BinaryenDataDropSetSegment'] -pub fn datadropsetsegment(expr Expression, segmentindex u32) - -[c: 'BinaryenMemoryCopyGetDest'] -pub fn memorycopygetdest(expr Expression) Expression - -[c: 'BinaryenMemoryCopySetDest'] -pub fn memorycopysetdest(expr Expression, destexpr Expression) - -[c: 'BinaryenMemoryCopyGetSource'] -pub fn memorycopygetsource(expr Expression) Expression - -[c: 'BinaryenMemoryCopySetSource'] -pub fn memorycopysetsource(expr Expression, sourceexpr Expression) - -[c: 'BinaryenMemoryCopyGetSize'] -pub fn memorycopygetsize(expr Expression) Expression - -[c: 'BinaryenMemoryCopySetSize'] -pub fn memorycopysetsize(expr Expression, sizeexpr Expression) - -[c: 'BinaryenMemoryFillGetDest'] -pub fn memoryfillgetdest(expr Expression) Expression - -[c: 'BinaryenMemoryFillSetDest'] -pub fn memoryfillsetdest(expr Expression, destexpr Expression) - -[c: 'BinaryenMemoryFillGetValue'] -pub fn memoryfillgetvalue(expr Expression) Expression - -[c: 'BinaryenMemoryFillSetValue'] -pub fn memoryfillsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenMemoryFillGetSize'] -pub fn memoryfillgetsize(expr Expression) Expression - -[c: 'BinaryenMemoryFillSetSize'] -pub fn memoryfillsetsize(expr Expression, sizeexpr Expression) - -[c: 'BinaryenRefIsGetOp'] -pub fn refisgetop(expr Expression) Op - -[c: 'BinaryenRefIsSetOp'] -pub fn refissetop(expr Expression, op Op) - -[c: 'BinaryenRefIsGetValue'] -pub fn refisgetvalue(expr Expression) Expression - -[c: 'BinaryenRefIsSetValue'] -pub fn refissetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenRefAsGetOp'] -pub fn refasgetop(expr Expression) Op - -[c: 'BinaryenRefAsSetOp'] -pub fn refassetop(expr Expression, op Op) - -[c: 'BinaryenRefAsGetValue'] -pub fn refasgetvalue(expr Expression) Expression - -[c: 'BinaryenRefAsSetValue'] -pub fn refassetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenRefFuncGetFunc'] -pub fn reffuncgetfunc(expr Expression) &i8 - -[c: 'BinaryenRefFuncSetFunc'] -pub fn reffuncsetfunc(expr Expression, funcname &i8) - -[c: 'BinaryenRefEqGetLeft'] -pub fn refeqgetleft(expr Expression) Expression - -[c: 'BinaryenRefEqSetLeft'] -pub fn refeqsetleft(expr Expression, left Expression) - -[c: 'BinaryenRefEqGetRight'] -pub fn refeqgetright(expr Expression) Expression - -[c: 'BinaryenRefEqSetRight'] -pub fn refeqsetright(expr Expression, right Expression) - -[c: 'BinaryenTryGetName'] -pub fn trygetname(expr Expression) &i8 - -[c: 'BinaryenTrySetName'] -pub fn trysetname(expr Expression, name &i8) - -[c: 'BinaryenTryGetBody'] -pub fn trygetbody(expr Expression) Expression - -[c: 'BinaryenTrySetBody'] -pub fn trysetbody(expr Expression, bodyexpr Expression) - -[c: 'BinaryenTryGetNumCatchTags'] -pub fn trygetnumcatchtags(expr Expression) Index - -[c: 'BinaryenTryGetNumCatchBodies'] -pub fn trygetnumcatchbodies(expr Expression) Index - -[c: 'BinaryenTryGetCatchTagAt'] -pub fn trygetcatchtagat(expr Expression, index Index) &i8 - -[c: 'BinaryenTrySetCatchTagAt'] -pub fn trysetcatchtagat(expr Expression, index Index, catchtag &i8) - -[c: 'BinaryenTryAppendCatchTag'] -pub fn tryappendcatchtag(expr Expression, catchtag &i8) Index - -[c: 'BinaryenTryInsertCatchTagAt'] -pub fn tryinsertcatchtagat(expr Expression, index Index, catchtag &i8) - -[c: 'BinaryenTryRemoveCatchTagAt'] -pub fn tryremovecatchtagat(expr Expression, index Index) &i8 - -[c: 'BinaryenTryGetCatchBodyAt'] -pub fn trygetcatchbodyat(expr Expression, index Index) Expression - -[c: 'BinaryenTrySetCatchBodyAt'] -pub fn trysetcatchbodyat(expr Expression, index Index, catchexpr Expression) - -[c: 'BinaryenTryAppendCatchBody'] -pub fn tryappendcatchbody(expr Expression, catchexpr Expression) Index - -[c: 'BinaryenTryInsertCatchBodyAt'] -pub fn tryinsertcatchbodyat(expr Expression, index Index, catchexpr Expression) - -[c: 'BinaryenTryRemoveCatchBodyAt'] -pub fn tryremovecatchbodyat(expr Expression, index Index) Expression - -[c: 'BinaryenTryHasCatchAll'] -pub fn tryhascatchall(expr Expression) bool - -[c: 'BinaryenTryGetDelegateTarget'] -pub fn trygetdelegatetarget(expr Expression) &i8 - -[c: 'BinaryenTrySetDelegateTarget'] -pub fn trysetdelegatetarget(expr Expression, delegatetarget &i8) - -[c: 'BinaryenTryIsDelegate'] -pub fn tryisdelegate(expr Expression) bool - -[c: 'BinaryenThrowGetTag'] -pub fn throwgettag(expr Expression) &i8 - -[c: 'BinaryenThrowSetTag'] -pub fn throwsettag(expr Expression, tagname &i8) - -[c: 'BinaryenThrowGetNumOperands'] -pub fn throwgetnumoperands(expr Expression) Index - -[c: 'BinaryenThrowGetOperandAt'] -pub fn throwgetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenThrowSetOperandAt'] -pub fn throwsetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenThrowAppendOperand'] -pub fn throwappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenThrowInsertOperandAt'] -pub fn throwinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenThrowRemoveOperandAt'] -pub fn throwremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenRethrowGetTarget'] -pub fn rethrowgettarget(expr Expression) &i8 - -[c: 'BinaryenRethrowSetTarget'] -pub fn rethrowsettarget(expr Expression, target &i8) - -[c: 'BinaryenTupleMakeGetNumOperands'] -pub fn tuplemakegetnumoperands(expr Expression) Index - -[c: 'BinaryenTupleMakeGetOperandAt'] -pub fn tuplemakegetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenTupleMakeSetOperandAt'] -pub fn tuplemakesetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenTupleMakeAppendOperand'] -pub fn tuplemakeappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenTupleMakeInsertOperandAt'] -pub fn tuplemakeinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenTupleMakeRemoveOperandAt'] -pub fn tuplemakeremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenTupleExtractGetTuple'] -pub fn tupleextractgettuple(expr Expression) Expression - -[c: 'BinaryenTupleExtractSetTuple'] -pub fn tupleextractsettuple(expr Expression, tupleexpr Expression) - -[c: 'BinaryenTupleExtractGetIndex'] -pub fn tupleextractgetindex(expr Expression) Index - -[c: 'BinaryenTupleExtractSetIndex'] -pub fn tupleextractsetindex(expr Expression, index Index) - -[c: 'BinaryenI31NewGetValue'] -pub fn i31newgetvalue(expr Expression) Expression - -[c: 'BinaryenI31NewSetValue'] -pub fn i31newsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenI31GetGetI31'] -pub fn i31getgeti31(expr Expression) Expression - -[c: 'BinaryenI31GetSetI31'] -pub fn i31getseti31(expr Expression, i31expr Expression) - -[c: 'BinaryenI31GetIsSigned'] -pub fn i31getissigned(expr Expression) bool - -[c: 'BinaryenI31GetSetSigned'] -pub fn i31getsetsigned(expr Expression, signed_ bool) - -[c: 'BinaryenCallRefGetNumOperands'] -pub fn callrefgetnumoperands(expr Expression) Index - -[c: 'BinaryenCallRefGetOperandAt'] -pub fn callrefgetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallRefSetOperandAt'] -pub fn callrefsetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallRefAppendOperand'] -pub fn callrefappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenCallRefInsertOperandAt'] -pub fn callrefinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenCallRefRemoveOperandAt'] -pub fn callrefremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenCallRefGetTarget'] -pub fn callrefgettarget(expr Expression) Expression - -[c: 'BinaryenCallRefSetTarget'] -pub fn callrefsettarget(expr Expression, targetexpr Expression) - -[c: 'BinaryenCallRefIsReturn'] -pub fn callrefisreturn(expr Expression) bool - -[c: 'BinaryenCallRefSetReturn'] -pub fn callrefsetreturn(expr Expression, isreturn bool) - -[c: 'BinaryenRefTestGetRef'] -pub fn reftestgetref(expr Expression) Expression - -[c: 'BinaryenRefTestSetRef'] -pub fn reftestsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenRefTestGetIntendedType'] -pub fn reftestgetintendedtype(expr Expression) HeapType - -[c: 'BinaryenRefTestSetIntendedType'] -pub fn reftestsetintendedtype(expr Expression, intendedtype HeapType) - -[c: 'BinaryenRefCastGetRef'] -pub fn refcastgetref(expr Expression) Expression - -[c: 'BinaryenRefCastSetRef'] -pub fn refcastsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenRefCastGetIntendedType'] -pub fn refcastgetintendedtype(expr Expression) HeapType - -[c: 'BinaryenRefCastSetIntendedType'] -pub fn refcastsetintendedtype(expr Expression, intendedtype HeapType) - -[c: 'BinaryenBrOnGetOp'] -pub fn brongetop(expr Expression) Op - -[c: 'BinaryenBrOnSetOp'] -pub fn bronsetop(expr Expression, op Op) - -[c: 'BinaryenBrOnGetName'] -pub fn brongetname(expr Expression) &i8 - -[c: 'BinaryenBrOnSetName'] -pub fn bronsetname(expr Expression, namestr &i8) - -[c: 'BinaryenBrOnGetRef'] -pub fn brongetref(expr Expression) Expression - -[c: 'BinaryenBrOnSetRef'] -pub fn bronsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenBrOnGetIntendedType'] -pub fn brongetintendedtype(expr Expression) HeapType - -[c: 'BinaryenBrOnSetIntendedType'] -pub fn bronsetintendedtype(expr Expression, intendedtype HeapType) - -[c: 'BinaryenStructNewGetNumOperands'] -pub fn structnewgetnumoperands(expr Expression) Index - -[c: 'BinaryenStructNewGetOperandAt'] -pub fn structnewgetoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenStructNewSetOperandAt'] -pub fn structnewsetoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenStructNewAppendOperand'] -pub fn structnewappendoperand(expr Expression, operandexpr Expression) Index - -[c: 'BinaryenStructNewInsertOperandAt'] -pub fn structnewinsertoperandat(expr Expression, index Index, operandexpr Expression) - -[c: 'BinaryenStructNewRemoveOperandAt'] -pub fn structnewremoveoperandat(expr Expression, index Index) Expression - -[c: 'BinaryenStructGetGetIndex'] -pub fn structgetgetindex(expr Expression) Index - -[c: 'BinaryenStructGetSetIndex'] -pub fn structgetsetindex(expr Expression, index Index) - -[c: 'BinaryenStructGetGetRef'] -pub fn structgetgetref(expr Expression) Expression - -[c: 'BinaryenStructGetSetRef'] -pub fn structgetsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStructGetIsSigned'] -pub fn structgetissigned(expr Expression) bool - -[c: 'BinaryenStructGetSetSigned'] -pub fn structgetsetsigned(expr Expression, signed_ bool) - -[c: 'BinaryenStructSetGetIndex'] -pub fn structsetgetindex(expr Expression) Index - -[c: 'BinaryenStructSetSetIndex'] -pub fn structsetsetindex(expr Expression, index Index) - -[c: 'BinaryenStructSetGetRef'] -pub fn structsetgetref(expr Expression) Expression - -[c: 'BinaryenStructSetSetRef'] -pub fn structsetsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStructSetGetValue'] -pub fn structsetgetvalue(expr Expression) Expression - -[c: 'BinaryenStructSetSetValue'] -pub fn structsetsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenArrayNewGetInit'] -pub fn arraynewgetinit(expr Expression) Expression - -[c: 'BinaryenArrayNewSetInit'] -pub fn arraynewsetinit(expr Expression, initexpr Expression) - -[c: 'BinaryenArrayNewGetSize'] -pub fn arraynewgetsize(expr Expression) Expression - -[c: 'BinaryenArrayNewSetSize'] -pub fn arraynewsetsize(expr Expression, sizeexpr Expression) - -[c: 'BinaryenArrayInitGetNumValues'] -pub fn arrayinitgetnumvalues(expr Expression) Index - -[c: 'BinaryenArrayInitGetValueAt'] -pub fn arrayinitgetvalueat(expr Expression, index Index) Expression - -[c: 'BinaryenArrayInitSetValueAt'] -pub fn arrayinitsetvalueat(expr Expression, index Index, valueexpr Expression) - -[c: 'BinaryenArrayInitAppendValue'] -pub fn arrayinitappendvalue(expr Expression, valueexpr Expression) Index - -[c: 'BinaryenArrayInitInsertValueAt'] -pub fn arrayinitinsertvalueat(expr Expression, index Index, valueexpr Expression) - -[c: 'BinaryenArrayInitRemoveValueAt'] -pub fn arrayinitremovevalueat(expr Expression, index Index) Expression - -[c: 'BinaryenArrayGetGetRef'] -pub fn arraygetgetref(expr Expression) Expression - -[c: 'BinaryenArrayGetSetRef'] -pub fn arraygetsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenArrayGetGetIndex'] -pub fn arraygetgetindex(expr Expression) Expression - -[c: 'BinaryenArrayGetSetIndex'] -pub fn arraygetsetindex(expr Expression, indexexpr Expression) - -[c: 'BinaryenArrayGetIsSigned'] -pub fn arraygetissigned(expr Expression) bool - -[c: 'BinaryenArrayGetSetSigned'] -pub fn arraygetsetsigned(expr Expression, signed_ bool) - -[c: 'BinaryenArraySetGetRef'] -pub fn arraysetgetref(expr Expression) Expression - -[c: 'BinaryenArraySetSetRef'] -pub fn arraysetsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenArraySetGetIndex'] -pub fn arraysetgetindex(expr Expression) Expression - -[c: 'BinaryenArraySetSetIndex'] -pub fn arraysetsetindex(expr Expression, indexexpr Expression) - -[c: 'BinaryenArraySetGetValue'] -pub fn arraysetgetvalue(expr Expression) Expression - -[c: 'BinaryenArraySetSetValue'] -pub fn arraysetsetvalue(expr Expression, valueexpr Expression) - -[c: 'BinaryenArrayLenGetRef'] -pub fn arraylengetref(expr Expression) Expression - -[c: 'BinaryenArrayLenSetRef'] -pub fn arraylensetref(expr Expression, refexpr Expression) - -[c: 'BinaryenArrayCopyGetDestRef'] -pub fn arraycopygetdestref(expr Expression) Expression - -[c: 'BinaryenArrayCopySetDestRef'] -pub fn arraycopysetdestref(expr Expression, destrefexpr Expression) - -[c: 'BinaryenArrayCopyGetDestIndex'] -pub fn arraycopygetdestindex(expr Expression) Expression - -[c: 'BinaryenArrayCopySetDestIndex'] -pub fn arraycopysetdestindex(expr Expression, destindexexpr Expression) - -[c: 'BinaryenArrayCopyGetSrcRef'] -pub fn arraycopygetsrcref(expr Expression) Expression - -[c: 'BinaryenArrayCopySetSrcRef'] -pub fn arraycopysetsrcref(expr Expression, srcrefexpr Expression) - -[c: 'BinaryenArrayCopyGetSrcIndex'] -pub fn arraycopygetsrcindex(expr Expression) Expression - -[c: 'BinaryenArrayCopySetSrcIndex'] -pub fn arraycopysetsrcindex(expr Expression, srcindexexpr Expression) - -[c: 'BinaryenArrayCopyGetLength'] -pub fn arraycopygetlength(expr Expression) Expression - -[c: 'BinaryenArrayCopySetLength'] -pub fn arraycopysetlength(expr Expression, lengthexpr Expression) - -[c: 'BinaryenStringNewGetOp'] -pub fn stringnewgetop(expr Expression) Op - -[c: 'BinaryenStringNewSetOp'] -pub fn stringnewsetop(expr Expression, op Op) - -[c: 'BinaryenStringNewGetPtr'] -pub fn stringnewgetptr(expr Expression) Expression - -[c: 'BinaryenStringNewSetPtr'] -pub fn stringnewsetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenStringNewGetLength'] -pub fn stringnewgetlength(expr Expression) Expression - -[c: 'BinaryenStringNewSetLength'] -pub fn stringnewsetlength(expr Expression, lengthexpr Expression) - -[c: 'BinaryenStringNewGetStart'] -pub fn stringnewgetstart(expr Expression) Expression - -[c: 'BinaryenStringNewSetStart'] -pub fn stringnewsetstart(expr Expression, startexpr Expression) - -[c: 'BinaryenStringNewGetEnd'] -pub fn stringnewgetend(expr Expression) Expression - -[c: 'BinaryenStringNewSetEnd'] -pub fn stringnewsetend(expr Expression, endexpr Expression) - -[c: 'BinaryenStringConstGetString'] -pub fn stringconstgetstring(expr Expression) &i8 - -[c: 'BinaryenStringConstSetString'] -pub fn stringconstsetstring(expr Expression, stringstr &i8) - -[c: 'BinaryenStringMeasureGetOp'] -pub fn stringmeasuregetop(expr Expression) Op - -[c: 'BinaryenStringMeasureSetOp'] -pub fn stringmeasuresetop(expr Expression, op Op) - -[c: 'BinaryenStringMeasureGetRef'] -pub fn stringmeasuregetref(expr Expression) Expression - -[c: 'BinaryenStringMeasureSetRef'] -pub fn stringmeasuresetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringEncodeGetOp'] -pub fn stringencodegetop(expr Expression) Op - -[c: 'BinaryenStringEncodeSetOp'] -pub fn stringencodesetop(expr Expression, op Op) - -[c: 'BinaryenStringEncodeGetRef'] -pub fn stringencodegetref(expr Expression) Expression - -[c: 'BinaryenStringEncodeSetRef'] -pub fn stringencodesetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringEncodeGetPtr'] -pub fn stringencodegetptr(expr Expression) Expression - -[c: 'BinaryenStringEncodeSetPtr'] -pub fn stringencodesetptr(expr Expression, ptrexpr Expression) - -[c: 'BinaryenStringEncodeGetStart'] -pub fn stringencodegetstart(expr Expression) Expression - -[c: 'BinaryenStringEncodeSetStart'] -pub fn stringencodesetstart(expr Expression, startexpr Expression) - -[c: 'BinaryenStringConcatGetLeft'] -pub fn stringconcatgetleft(expr Expression) Expression - -[c: 'BinaryenStringConcatSetLeft'] -pub fn stringconcatsetleft(expr Expression, leftexpr Expression) - -[c: 'BinaryenStringConcatGetRight'] -pub fn stringconcatgetright(expr Expression) Expression - -[c: 'BinaryenStringConcatSetRight'] -pub fn stringconcatsetright(expr Expression, rightexpr Expression) - -[c: 'BinaryenStringEqGetLeft'] -pub fn stringeqgetleft(expr Expression) Expression - -[c: 'BinaryenStringEqSetLeft'] -pub fn stringeqsetleft(expr Expression, leftexpr Expression) - -[c: 'BinaryenStringEqGetRight'] -pub fn stringeqgetright(expr Expression) Expression - -[c: 'BinaryenStringEqSetRight'] -pub fn stringeqsetright(expr Expression, rightexpr Expression) - -[c: 'BinaryenStringAsGetOp'] -pub fn stringasgetop(expr Expression) Op - -[c: 'BinaryenStringAsSetOp'] -pub fn stringassetop(expr Expression, op Op) - -[c: 'BinaryenStringAsGetRef'] -pub fn stringasgetref(expr Expression) Expression - -[c: 'BinaryenStringAsSetRef'] -pub fn stringassetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringWTF8AdvanceGetRef'] -pub fn stringwtf8advancegetref(expr Expression) Expression - -[c: 'BinaryenStringWTF8AdvanceSetRef'] -pub fn stringwtf8advancesetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringWTF8AdvanceGetPos'] -pub fn stringwtf8advancegetpos(expr Expression) Expression - -[c: 'BinaryenStringWTF8AdvanceSetPos'] -pub fn stringwtf8advancesetpos(expr Expression, posexpr Expression) - -[c: 'BinaryenStringWTF8AdvanceGetBytes'] -pub fn stringwtf8advancegetbytes(expr Expression) Expression - -[c: 'BinaryenStringWTF8AdvanceSetBytes'] -pub fn stringwtf8advancesetbytes(expr Expression, bytesexpr Expression) - -[c: 'BinaryenStringWTF16GetGetRef'] -pub fn stringwtf16getgetref(expr Expression) Expression - -[c: 'BinaryenStringWTF16GetSetRef'] -pub fn stringwtf16getsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringWTF16GetGetPos'] -pub fn stringwtf16getgetpos(expr Expression) Expression - -[c: 'BinaryenStringWTF16GetSetPos'] -pub fn stringwtf16getsetpos(expr Expression, posexpr Expression) - -[c: 'BinaryenStringIterNextGetRef'] -pub fn stringiternextgetref(expr Expression) Expression - -[c: 'BinaryenStringIterNextSetRef'] -pub fn stringiternextsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringIterMoveGetOp'] -pub fn stringitermovegetop(expr Expression) Op - -[c: 'BinaryenStringIterMoveSetOp'] -pub fn stringitermovesetop(expr Expression, op Op) - -[c: 'BinaryenStringIterMoveGetRef'] -pub fn stringitermovegetref(expr Expression) Expression - -[c: 'BinaryenStringIterMoveSetRef'] -pub fn stringitermovesetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringIterMoveGetNum'] -pub fn stringitermovegetnum(expr Expression) Expression - -[c: 'BinaryenStringIterMoveSetNum'] -pub fn stringitermovesetnum(expr Expression, numexpr Expression) - -[c: 'BinaryenStringSliceWTFGetOp'] -pub fn stringslicewtfgetop(expr Expression) Op - -[c: 'BinaryenStringSliceWTFSetOp'] -pub fn stringslicewtfsetop(expr Expression, op Op) - -[c: 'BinaryenStringSliceWTFGetRef'] -pub fn stringslicewtfgetref(expr Expression) Expression - -[c: 'BinaryenStringSliceWTFSetRef'] -pub fn stringslicewtfsetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringSliceWTFGetStart'] -pub fn stringslicewtfgetstart(expr Expression) Expression - -[c: 'BinaryenStringSliceWTFSetStart'] -pub fn stringslicewtfsetstart(expr Expression, startexpr Expression) - -[c: 'BinaryenStringSliceWTFGetEnd'] -pub fn stringslicewtfgetend(expr Expression) Expression - -[c: 'BinaryenStringSliceWTFSetEnd'] -pub fn stringslicewtfsetend(expr Expression, endexpr Expression) - -[c: 'BinaryenStringSliceIterGetRef'] -pub fn stringsliceitergetref(expr Expression) Expression - -[c: 'BinaryenStringSliceIterSetRef'] -pub fn stringsliceitersetref(expr Expression, refexpr Expression) - -[c: 'BinaryenStringSliceIterGetNum'] -pub fn stringsliceitergetnum(expr Expression) Expression - -[c: 'BinaryenStringSliceIterSetNum'] -pub fn stringsliceitersetnum(expr Expression, numexpr Expression) - -type Function = voidptr - -[c: 'BinaryenAddFunction'] -pub fn addfunction(module_ Module, name &i8, params Type, results Type, vartypes &Type, numvartypes Index, body Expression) Function - -[c: 'BinaryenGetFunction'] -pub fn getfunction(module_ Module, name &i8) Function - -[c: 'BinaryenRemoveFunction'] -pub fn removefunction(module_ Module, name &i8) - -[c: 'BinaryenGetNumFunctions'] -pub fn getnumfunctions(module_ Module) Index - -[c: 'BinaryenGetFunctionByIndex'] -pub fn getfunctionbyindex(module_ Module, index Index) Function - -[c: 'BinaryenAddFunctionImport'] -pub fn addfunctionimport(module_ Module, internalname &i8, externalmodulename &i8, externalbasename &i8, params Type, results Type) - -[c: 'BinaryenAddTableImport'] -pub fn addtableimport(module_ Module, internalname &i8, externalmodulename &i8, externalbasename &i8) - -[c: 'BinaryenAddMemoryImport'] -pub fn addmemoryimport(module_ Module, internalname &i8, externalmodulename &i8, externalbasename &i8, shared_ u8) - -[c: 'BinaryenAddGlobalImport'] -pub fn addglobalimport(module_ Module, internalname &i8, externalmodulename &i8, externalbasename &i8, globaltype Type, mutable_ bool) - -[c: 'BinaryenAddTagImport'] -pub fn addtagimport(module_ Module, internalname &i8, externalmodulename &i8, externalbasename &i8, params Type, results Type) - -type Export = voidptr - -[c: 'BinaryenAddExport'] -pub fn addexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenAddFunctionExport'] -pub fn addfunctionexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenAddTableExport'] -pub fn addtableexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenAddMemoryExport'] -pub fn addmemoryexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenAddGlobalExport'] -pub fn addglobalexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenAddTagExport'] -pub fn addtagexport(module_ Module, internalname &i8, externalname &i8) Export - -[c: 'BinaryenGetExport'] -pub fn getexport(module_ Module, externalname &i8) Export - -[c: 'BinaryenRemoveExport'] -pub fn removeexport(module_ Module, externalname &i8) - -[c: 'BinaryenGetNumExports'] -pub fn getnumexports(module_ Module) Index - -[c: 'BinaryenGetExportByIndex'] -pub fn getexportbyindex(module_ Module, index Index) Export - -type Global = voidptr - -[c: 'BinaryenAddGlobal'] -pub fn addglobal(module_ Module, name &i8, type_ Type, mutable_ bool, init Expression) Global - -[c: 'BinaryenGetGlobal'] -pub fn getglobal(module_ Module, name &i8) Global - -[c: 'BinaryenRemoveGlobal'] -pub fn removeglobal(module_ Module, name &i8) - -[c: 'BinaryenGetNumGlobals'] -pub fn getnumglobals(module_ Module) Index - -[c: 'BinaryenGetGlobalByIndex'] -pub fn getglobalbyindex(module_ Module, index Index) Global - -type Tag = voidptr - -[c: 'BinaryenAddTag'] -pub fn addtag(module_ Module, name &i8, params Type, results Type) Tag - -[c: 'BinaryenGetTag'] -pub fn gettag(module_ Module, name &i8) Tag - -[c: 'BinaryenRemoveTag'] -pub fn removetag(module_ Module, name &i8) - -type Table = voidptr - -[c: 'BinaryenAddTable'] -pub fn addtable(module_ Module, table &i8, initial Index, maximum Index, tabletype Type) Table - -[c: 'BinaryenRemoveTable'] -pub fn removetable(module_ Module, table &i8) - -[c: 'BinaryenGetNumTables'] -pub fn getnumtables(module_ Module) Index - -[c: 'BinaryenGetTable'] -pub fn gettable(module_ Module, name &i8) Table - -[c: 'BinaryenGetTableByIndex'] -pub fn gettablebyindex(module_ Module, index Index) Table - -type ElementSegment = voidptr - -[c: 'BinaryenAddActiveElementSegment'] -pub fn addactiveelementsegment(module_ Module, table &i8, name &i8, funcnames &&u8, numfuncnames Index, offset Expression) ElementSegment - -[c: 'BinaryenAddPassiveElementSegment'] -pub fn addpassiveelementsegment(module_ Module, name &i8, funcnames &&u8, numfuncnames Index) ElementSegment - -[c: 'BinaryenRemoveElementSegment'] -pub fn removeelementsegment(module_ Module, name &i8) - -[c: 'BinaryenGetNumElementSegments'] -pub fn getnumelementsegments(module_ Module) Index - -[c: 'BinaryenGetElementSegment'] -pub fn getelementsegment(module_ Module, name &i8) ElementSegment - -[c: 'BinaryenGetElementSegmentByIndex'] -pub fn getelementsegmentbyindex(module_ Module, index Index) ElementSegment - -[c: 'BinaryenSetMemory'] -pub fn setmemory(module_ Module, initial Index, maximum Index, exportname &i8, segments &&u8, segmentpassive &bool, segmentoffsets &Expression, segmentsizes &Index, numsegments Index, shared_ bool, memory64 bool, name &i8) - -[c: 'BinaryenHasMemory'] -pub fn hasmemory(module_ Module) bool - -[c: 'BinaryenMemoryGetInitial'] -pub fn memorygetinitial(module_ Module, name &i8) Index - -[c: 'BinaryenMemoryHasMax'] -pub fn memoryhasmax(module_ Module, name &i8) bool - -[c: 'BinaryenMemoryGetMax'] -pub fn memorygetmax(module_ Module, name &i8) Index - -[c: 'BinaryenMemoryImportGetModule'] -pub fn memoryimportgetmodule(module_ Module, name &i8) &i8 - -[c: 'BinaryenMemoryImportGetBase'] -pub fn memoryimportgetbase(module_ Module, name &i8) &i8 - -[c: 'BinaryenMemoryIsshared_'] -pub fn memoryisshared_(module_ Module, name &i8) bool - -[c: 'BinaryenMemoryIs64'] -pub fn memoryis64(module_ Module, name &i8) bool - -[c: 'BinaryenGetNumMemorySegments'] -pub fn getnummemorysegments(module_ Module) u32 - -[c: 'BinaryenGetMemorySegmentByteOffset'] -pub fn getmemorysegmentbyteoffset(module_ Module, id Index) u32 - -[c: 'BinaryenGetMemorySegmentByteLength'] -pub fn getmemorysegmentbytelength(module_ Module, id Index) usize - -[c: 'BinaryenGetMemorySegmentPassive'] -pub fn getmemorysegmentpassive(module_ Module, id Index) bool - -[c: 'BinaryenCopyMemorySegmentData'] -pub fn copymemorysegmentdata(module_ Module, id Index, buffer &i8) - -[c: 'BinaryenSetStart'] -pub fn setstart(module_ Module, start Function) - -[c: 'BinaryenModuleGetFeatures'] -pub fn modulegetfeatures(module_ Module) Features - -[c: 'BinaryenModuleSetFeatures'] -pub fn modulesetfeatures(module_ Module, features Features) - -[c: 'BinaryenModuleParse'] -pub fn moduleparse(text &i8) Module - -[c: 'BinaryenModulePrint'] -pub fn moduleprint(module_ Module) - -[c: 'BinaryenModulePrintStackIR'] -pub fn moduleprintstackir(module_ Module, optimize bool) - -[c: 'BinaryenModulePrintAsmjs'] -pub fn moduleprintasmjs(module_ Module) - -[c: 'BinaryenModuleValidate'] -pub fn modulevalidate(module_ Module) bool - -[c: 'BinaryenModuleOptimize'] -pub fn moduleoptimize(module_ Module) - -[c: 'BinaryenModuleUpdateMaps'] -pub fn moduleupdatemaps(module_ Module) - -[c: 'BinaryenGetOptimizeLevel'] -pub fn getoptimizelevel() int - -[c: 'BinaryenSetOptimizeLevel'] -pub fn setoptimizelevel(level int) - -[c: 'BinaryenGetShrinkLevel'] -pub fn getshrinklevel() int - -[c: 'BinaryenSetShrinkLevel'] -pub fn setshrinklevel(level int) - -[c: 'BinaryenGetDebugInfo'] -pub fn getdebuginfo() bool - -[c: 'BinaryenSetDebugInfo'] -pub fn setdebuginfo(on bool) - -[c: 'BinaryenGetLowMemoryUnused'] -pub fn getlowmemoryunused() bool - -[c: 'BinaryenSetLowMemoryUnused'] -pub fn setlowmemoryunused(on bool) - -[c: 'BinaryenGetZeroFilledMemory'] -pub fn getzerofilledmemory() bool - -[c: 'BinaryenSetZeroFilledMemory'] -pub fn setzerofilledmemory(on bool) - -[c: 'BinaryenGetFastMath'] -pub fn getfastmath() bool - -[c: 'BinaryenSetFastMath'] -pub fn setfastmath(value bool) - -[c: 'BinaryenGetPassArgument'] -pub fn getpassargument(name &i8) &i8 - -[c: 'BinaryenSetPassArgument'] -pub fn setpassargument(name &i8, value &i8) - -[c: 'BinaryenClearPassArguments'] -pub fn clearpassarguments() - -[c: 'BinaryenGetAlwaysInlineMaxSize'] -pub fn getalwaysinlinemaxsize() Index - -[c: 'BinaryenSetAlwaysInlineMaxSize'] -pub fn setalwaysinlinemaxsize(size Index) - -[c: 'BinaryenGetFlexibleInlineMaxSize'] -pub fn getflexibleinlinemaxsize() Index - -[c: 'BinaryenSetFlexibleInlineMaxSize'] -pub fn setflexibleinlinemaxsize(size Index) - -[c: 'BinaryenGetOneCallerInlineMaxSize'] -pub fn getonecallerinlinemaxsize() Index - -[c: 'BinaryenSetOneCallerInlineMaxSize'] -pub fn setonecallerinlinemaxsize(size Index) - -[c: 'BinaryenGetAllowInliningFunctionsWithLoops'] -pub fn getallowinliningfunctionswithloops() bool - -[c: 'BinaryenSetAllowInliningFunctionsWithLoops'] -pub fn setallowinliningfunctionswithloops(enabled bool) - -[c: 'BinaryenModuleRunPasses'] -pub fn modulerunpasses(module_ Module, passes &&u8, numpasses Index) - -[c: 'BinaryenModuleAutoDrop'] -pub fn moduleautodrop(module_ Module) - -[c: 'BinaryenModuleWrite'] -pub fn modulewrite(module_ Module, output &i8, outputsize usize) usize - -[c: 'BinaryenModuleWriteText'] -pub fn modulewritetext(module_ Module, output &i8, outputsize usize) usize - -[c: 'BinaryenModuleWriteStackIR'] -pub fn modulewritestackir(module_ Module, output &i8, outputsize usize, optimize bool) usize - -pub struct BufferSizes { -pub: - outputBytes usize - sourceMapBytes usize -} - -[c: 'BinaryenModuleWriteWithSourceMap'] -pub fn modulewritewithsourcemap(module_ Module, url &i8, output &i8, outputsize usize, sourcemap &i8, sourcemapsize usize) BufferSizes - -pub struct ModuleAllocateAndWriteResult { -pub: - binary voidptr - binaryBytes usize - sourceMap &i8 -} - -[c: 'BinaryenModuleAllocateAndWrite'] -pub fn moduleallocateandwrite(module_ Module, sourcemapurl &i8) ModuleAllocateAndWriteResult - -[c: 'BinaryenModuleAllocateAndWriteText'] -pub fn moduleallocateandwritetext(module_ Module) &i8 - -[c: 'BinaryenModuleAllocateAndWriteStackIR'] -pub fn moduleallocateandwritestackir(module_ Module, optimize bool) &i8 - -[c: 'BinaryenModuleRead'] -pub fn moduleread(input &i8, inputsize usize) Module - -[c: 'BinaryenModuleInterpret'] -pub fn moduleinterpret(module_ Module) - -[c: 'BinaryenModuleAddDebugInfoFileName'] -pub fn moduleadddebuginfofilename(module_ Module, filename &i8) Index - -[c: 'BinaryenModuleGetDebugInfoFileName'] -pub fn modulegetdebuginfofilename(module_ Module, index Index) &i8 - -[c: 'BinaryenFunctionGetName'] -pub fn functiongetname(func Function) &i8 - -[c: 'BinaryenFunctionGetParams'] -pub fn functiongetparams(func Function) Type - -[c: 'BinaryenFunctionGetResults'] -pub fn functiongetresults(func Function) Type - -[c: 'BinaryenFunctionGetNumVars'] -pub fn functiongetnumvars(func Function) Index - -[c: 'BinaryenFunctionGetVar'] -pub fn functiongetvar(func Function, index Index) Type - -[c: 'BinaryenFunctionGetNumLocals'] -pub fn functiongetnumlocals(func Function) Index - -[c: 'BinaryenFunctionHasLocalName'] -pub fn functionhaslocalname(func Function, index Index) bool - -[c: 'BinaryenFunctionGetLocalName'] -pub fn functiongetlocalname(func Function, index Index) &i8 - -[c: 'BinaryenFunctionSetLocalName'] -pub fn functionsetlocalname(func Function, index Index, name &i8) - -[c: 'BinaryenFunctionGetBody'] -pub fn functiongetbody(func Function) Expression - -[c: 'BinaryenFunctionSetBody'] -pub fn functionsetbody(func Function, body Expression) - -[c: 'BinaryenFunctionOptimize'] -pub fn functionoptimize(func Function, module_ Module) - -[c: 'BinaryenFunctionRunPasses'] -pub fn functionrunpasses(func Function, module_ Module, passes &&u8, numpasses Index) - -[c: 'BinaryenFunctionSetDebugLocation'] -pub fn functionsetdebuglocation(func Function, expr Expression, fileindex Index, linenumber Index, columnnumber Index) - -[c: 'BinaryenTableGetName'] -pub fn tablegetname(table Table) &i8 - -[c: 'BinaryenTableSetName'] -pub fn tablesetname(table Table, name &i8) - -[c: 'BinaryenTableGetInitial'] -pub fn tablegetinitial(table Table) Index - -[c: 'BinaryenTableSetInitial'] -pub fn tablesetinitial(table Table, initial Index) - -[c: 'BinaryenTableHasMax'] -pub fn tablehasmax(table Table) bool - -[c: 'BinaryenTableGetMax'] -pub fn tablegetmax(table Table) Index - -[c: 'BinaryenTableSetMax'] -pub fn tablesetmax(table Table, max Index) - -[c: 'BinaryenElementSegmentGetName'] -pub fn elementsegmentgetname(elem ElementSegment) &i8 - -[c: 'BinaryenElementSegmentSetName'] -pub fn elementsegmentsetname(elem ElementSegment, name &i8) - -[c: 'BinaryenElementSegmentGetTable'] -pub fn elementsegmentgettable(elem ElementSegment) &i8 - -[c: 'BinaryenElementSegmentSetTable'] -pub fn elementsegmentsettable(elem ElementSegment, table &i8) - -[c: 'BinaryenElementSegmentGetOffset'] -pub fn elementsegmentgetoffset(elem ElementSegment) Expression - -[c: 'BinaryenElementSegmentGetLength'] -pub fn elementsegmentgetlength(elem ElementSegment) Index - -[c: 'BinaryenElementSegmentGetData'] -pub fn elementsegmentgetdata(elem ElementSegment, dataid Index) &i8 - -[c: 'BinaryenElementSegmentIsPassive'] -pub fn elementsegmentispassive(elem ElementSegment) bool - -[c: 'BinaryenGlobalGetName'] -pub fn globalgetname(global Global) &i8 - -[c: 'BinaryenGlobalGetType'] -pub fn globalgettype(global Global) Type - -[c: 'BinaryenGlobalIsMutable'] -pub fn globalismutable(global Global) bool - -[c: 'BinaryenGlobalGetInitExpr'] -pub fn globalgetinitexpr(global Global) Expression - -[c: 'BinaryenTagGetName'] -pub fn taggetname(tag Tag) &i8 - -[c: 'BinaryenTagGetParams'] -pub fn taggetparams(tag Tag) Type - -[c: 'BinaryenTagGetResults'] -pub fn taggetresults(tag Tag) Type - -[c: 'BinaryenFunctionImportGetModule'] -pub fn functionimportgetmodule(import_ Function) &i8 - -[c: 'BinaryenTableImportGetModule'] -pub fn tableimportgetmodule(import_ Table) &i8 - -[c: 'BinaryenGlobalImportGetModule'] -pub fn globalimportgetmodule(import_ Global) &i8 - -[c: 'BinaryenTagImportGetModule'] -pub fn tagimportgetmodule(import_ Tag) &i8 - -[c: 'BinaryenFunctionImportGetBase'] -pub fn functionimportgetbase(import_ Function) &i8 - -[c: 'BinaryenTableImportGetBase'] -pub fn tableimportgetbase(import_ Table) &i8 - -[c: 'BinaryenGlobalImportGetBase'] -pub fn globalimportgetbase(import_ Global) &i8 - -[c: 'BinaryenTagImportGetBase'] -pub fn tagimportgetbase(import_ Tag) &i8 - -[c: 'BinaryenExportGetKind'] -pub fn exportgetkind(export_ Export) ExternalKind - -[c: 'BinaryenExportGetName'] -pub fn exportgetname(export_ Export) &i8 - -[c: 'BinaryenExportGetValue'] -pub fn exportgetvalue(export_ Export) &i8 - -[c: 'BinaryenAddCustomSection'] -pub fn addcustomsection(module_ Module, name &i8, contents &i8, contentssize Index) - -type SideEffects = u32 - -[c: 'BinaryenSideEffectNone'] -pub fn sideeffectnone() SideEffects - -[c: 'BinaryenSideEffectBranches'] -pub fn sideeffectbranches() SideEffects - -[c: 'BinaryenSideEffectCalls'] -pub fn sideeffectcalls() SideEffects - -[c: 'BinaryenSideEffectReadsLocal'] -pub fn sideeffectreadslocal() SideEffects - -[c: 'BinaryenSideEffectWritesLocal'] -pub fn sideeffectwriteslocal() SideEffects - -[c: 'BinaryenSideEffectReadsGlobal'] -pub fn sideeffectreadsglobal() SideEffects - -[c: 'BinaryenSideEffectWritesGlobal'] -pub fn sideeffectwritesglobal() SideEffects - -[c: 'BinaryenSideEffectReadsMemory'] -pub fn sideeffectreadsmemory() SideEffects - -[c: 'BinaryenSideEffectWritesMemory'] -pub fn sideeffectwritesmemory() SideEffects - -[c: 'BinaryenSideEffectReadsTable'] -pub fn sideeffectreadstable() SideEffects - -[c: 'BinaryenSideEffectWritesTable'] -pub fn sideeffectwritestable() SideEffects - -[c: 'BinaryenSideEffectImplicitTrap'] -pub fn sideeffectimplicittrap() SideEffects - -[c: 'BinaryenSideEffectTrapsNeverHappen'] -pub fn sideeffecttrapsneverhappen() SideEffects - -[c: 'BinaryenSideEffectIsAtomic'] -pub fn sideeffectisatomic() SideEffects - -[c: 'BinaryenSideEffectThrows'] -pub fn sideeffectthrows() SideEffects - -[c: 'BinaryenSideEffectDanglingPop'] -pub fn sideeffectdanglingpop() SideEffects - -[c: 'BinaryenSideEffectAny'] -pub fn sideeffectany() SideEffects - -[c: 'BinaryenExpressionGetSideEffects'] -pub fn expressiongetsideeffects(expr Expression, module_ Module) SideEffects - -type Relooper = voidptr -type RelooperBlock = voidptr - -[c: 'RelooperCreate'] -pub fn reloopercreate(module_ Module) Relooper - -[c: 'RelooperAddBlock'] -pub fn relooperaddblock(relooper Relooper, code Expression) RelooperBlock - -[c: 'RelooperAddBranch'] -pub fn relooperaddbranch(from RelooperBlock, to RelooperBlock, condition Expression, code Expression) - -[c: 'RelooperAddBlockWithSwitch'] -pub fn relooperaddblockwithswitch(relooper Relooper, code Expression, condition Expression) RelooperBlock - -[c: 'RelooperAddBranchForSwitch'] -pub fn relooperaddbranchforswitch(from RelooperBlock, to RelooperBlock, indexes &Index, numindexes Index, code Expression) - -[c: 'RelooperRenderAndDispose'] -pub fn relooperrenderanddispose(relooper Relooper, entry RelooperBlock, labelhelper Index) Expression - -type ExpressionRunner = voidptr -type ExpressionRunnerFlags = u32 - -[c: 'ExpressionRunnerFlagsDefault'] -pub fn expressionrunnerflagsdefault() ExpressionRunnerFlags - -[c: 'ExpressionRunnerFlagsPreserveSideeffects'] -pub fn expressionrunnerflagspreservesideeffects() ExpressionRunnerFlags - -[c: 'ExpressionRunnerFlagsTraverseCalls'] -pub fn expressionrunnerflagstraversecalls() ExpressionRunnerFlags - -[c: 'ExpressionRunnerCreate'] -pub fn expressionrunnercreate(module_ Module, flags ExpressionRunnerFlags, maxdepth Index, maxloopiterations Index) ExpressionRunner - -[c: 'ExpressionRunnerSetLocalValue'] -pub fn expressionrunnersetlocalvalue(runner ExpressionRunner, index Index, value Expression) bool - -[c: 'ExpressionRunnerSetGlobalValue'] -pub fn expressionrunnersetglobalvalue(runner ExpressionRunner, name &i8, value Expression) bool - -[c: 'ExpressionRunnerRunAndDispose'] -pub fn expressionrunnerrunanddispose(runner ExpressionRunner, expr Expression) Expression - -type TypeBuilder = voidptr -type TypeBuilderErrorReason = u32 - -[c: 'TypeBuilderErrorReasonSelfSupertype'] -pub fn typebuildererrorreasonselfsupertype() TypeBuilderErrorReason - -[c: 'TypeBuilderErrorReasonInvalidSupertype'] -pub fn typebuildererrorreasoninvalidsupertype() TypeBuilderErrorReason - -[c: 'TypeBuilderErrorReasonForwardSupertypeReference'] -pub fn typebuildererrorreasonforwardsupertypereference() TypeBuilderErrorReason - -[c: 'TypeBuilderErrorReasonForwardChildReference'] -pub fn typebuildererrorreasonforwardchildreference() TypeBuilderErrorReason - -type BasicHeapType = u32 - -[c: 'TypeBuilderCreate'] -pub fn typebuildercreate(size Index) TypeBuilder - -[c: 'TypeBuilderGrow'] -pub fn typebuildergrow(builder TypeBuilder, count Index) - -[c: 'TypeBuilderGetSize'] -pub fn typebuildergetsize(builder TypeBuilder) Index - -[c: 'TypeBuilderSetBasicHeapType'] -pub fn typebuildersetbasicheaptype(builder TypeBuilder, index Index, basicheaptype BasicHeapType) - -[c: 'TypeBuilderSetSignatureType'] -pub fn typebuildersetsignaturetype(builder TypeBuilder, index Index, paramtypes Type, resulttypes Type) - -[c: 'TypeBuilderSetStructType'] -pub fn typebuildersetstructtype(builder TypeBuilder, index Index, fieldtypes &Type, fieldpackedtypes &Type, fieldmutables &bool, numfields int) - -[c: 'TypeBuilderSetArrayType'] -pub fn typebuildersetarraytype(builder TypeBuilder, index Index, elementtype Type, elementpackedtype PackedType, elementmutable int) - -[c: 'TypeBuilderIsBasic'] -pub fn typebuilderisbasic(builder TypeBuilder, index Index) bool - -[c: 'TypeBuilderGetBasic'] -pub fn typebuildergetbasic(builder TypeBuilder, index Index) BasicHeapType - -[c: 'TypeBuilderGetTempHeapType'] -pub fn typebuildergettempheaptype(builder TypeBuilder, index Index) HeapType - -[c: 'TypeBuilderGetTempTupleType'] -pub fn typebuildergettemptupletype(builder TypeBuilder, types &Type, numtypes Index) Type - -[c: 'TypeBuilderGetTempRefType'] -pub fn typebuildergettempreftype(builder TypeBuilder, heaptype HeapType, nullable int) Type - -[c: 'TypeBuilderSetSubType'] -pub fn typebuildersetsubtype(builder TypeBuilder, index Index, supertype HeapType) - -[c: 'TypeBuilderCreateRecGroup'] -pub fn typebuildercreaterecgroup(builder TypeBuilder, index Index, length Index) - -[c: 'TypeBuilderBuildAndDispose'] -pub fn typebuilderbuildanddispose(builder TypeBuilder, heaptypes &HeapType, errorindex &Index, errorreason &TypeBuilderErrorReason) bool - -[c: 'ModuleSetTypeName'] -pub fn modulesettypename(module_ Module, heaptype HeapType, name &i8) - -[c: 'ModuleSetFieldName'] -pub fn modulesetfieldname(module_ Module, heaptype HeapType, index Index, name &i8) - -[c: 'BinaryenSetColorsEnabled'] -pub fn setcolorsenabled(enabled bool) - -[c: 'BinaryenAreColorsEnabled'] -pub fn arecolorsenabled() bool diff --git a/vlib/v/gen/wasm/cast.v b/vlib/v/gen/wasm/cast.v deleted file mode 100644 index 21d201bc79..0000000000 --- a/vlib/v/gen/wasm/cast.v +++ /dev/null @@ -1,91 +0,0 @@ -module wasm - -import v.ast -import v.gen.wasm.binaryen - -fn (mut g Gen) is_signed(typ ast.Type) bool { - if typ.is_pure_float() { - return true - } - return typ.is_signed() -} - -fn (mut g Gen) unary_cast(from binaryen.Type, is_signed bool, to binaryen.Type) binaryen.Op { - if is_signed { - match from { - type_i32 { - match to { - type_i64 { return binaryen.extendsint32() } - type_f32 { return binaryen.convertsint32tofloat32() } - type_f64 { return binaryen.convertsint32tofloat64() } - else {} - } - } - type_i64 { - match to { - type_i32 { return binaryen.wrapint64() } - type_f32 { return binaryen.convertsint64tofloat32() } - type_f64 { return binaryen.convertsint64tofloat64() } - else {} - } - } - type_f32 { - match to { - type_i32 { return binaryen.truncsfloat32toint32() } - type_i64 { return binaryen.truncsfloat32toint64() } - type_f64 { return binaryen.promotefloat32() } - else {} - } - } - type_f64 { - match to { - type_i32 { return binaryen.truncsfloat64toint32() } - type_i64 { return binaryen.truncsfloat64toint64() } - type_f32 { return binaryen.demotefloat64() } - else {} - } - } - else {} - } - } else { - match from { - type_i32 { - match to { - type_i64 { return binaryen.extenduint32() } - type_f32 { return binaryen.convertuint32tofloat32() } - type_f64 { return binaryen.convertuint32tofloat64() } - else {} - } - } - type_i64 { - match to { - type_i32 { return binaryen.wrapint64() } - type_f32 { return binaryen.convertuint64tofloat32() } - type_f64 { return binaryen.convertuint64tofloat64() } - else {} - } - } - else {} - } - } - g.w_error('bad cast: from ${from} (is signed: ${is_signed}) to ${to}') -} - -fn (mut g Gen) cast_t(expr binaryen.Expression, from ast.Type, to ast.Type) binaryen.Expression { - return g.cast(expr, g.get_wasm_type(from), g.is_signed(from), g.get_wasm_type(to)) -} - -fn (mut g Gen) cast(expr binaryen.Expression, from binaryen.Type, is_signed bool, to binaryen.Type) binaryen.Expression { - if from == to { - return expr - } - - // In the official spec, integers are represented in twos complement. - // WebAssembly does not keep signedness information in it's types - // and uses instructions with variants for signed or unsigned values. - // - // You only need to know if the original type is signed or not to - // perform casting. - - return binaryen.unary(g.mod, g.unary_cast(from, is_signed, to), expr) -} diff --git a/vlib/v/gen/wasm/gen.v b/vlib/v/gen/wasm/gen.v index f272768f41..7aff12ffdc 100644 --- a/vlib/v/gen/wasm/gen.v +++ b/vlib/v/gen/wasm/gen.v @@ -1,3 +1,6 @@ +// Copyright (c) 2023 l-m.dev. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. module wasm import v.ast @@ -6,7 +9,8 @@ import v.util import v.token import v.errors import v.eval -import v.gen.wasm.binaryen +import v.gen.wasm.serialise +import wasm import os [heap; minify] @@ -15,50 +19,47 @@ pub struct Gen { pref &pref.Preferences = unsafe { nil } // Preferences shared from V struct files []&ast.File mut: - file_path string // current ast.File path - file_path_idx int // current binaryen debug info index, see `BinaryenModuleAddDebugInfoFileName` - warnings []errors.Warning - errors []errors.Error - table &ast.Table = unsafe { nil } - eval eval.Eval - enum_vals map[string]Enum + file_path string // current ast.File path + warnings []errors.Warning + errors []errors.Error + table &ast.Table = unsafe { nil } + eval eval.Eval + enum_vals map[string]Enum // - bp_idx int // Base pointer temporary's index for function, if needed (-1 for none) - stack_frame int // Size of the current stack frame, if needed - mod binaryen.Module // Current Binaryen WebAssembly module - curr_ret []ast.Type // Current return value, multi returns will be split into an array - local_temporaries []Temporary // Local WebAssembly temporaries, referenced with an index - local_addresses map[string]Stack // Local stack structures relative to `bp_idx` - structs map[ast.Type]StructInfo // Cached struct field offsets - // - lbl int - for_labels []string // A stack of strings containing the names of blocks/loops to break/continue to - stack_patches []BlockPatch - needs_stack bool // If true, will use `memory` and `__vsp` - constant_data []ConstantData - constant_data_offset int = 1024 // Low 1KiB of data unused, for optimisations - module_import_namespace string // `[wasm_import_namespace: 'wasi_snapshot_preview1']` else `env` - globals map[string]GlobalData + mod wasm.Module + pool serialise.Pool + func wasm.Function + local_vars []Var + global_vars map[string]Global + ret_rvars []Var + ret ast.Type + ret_types []ast.Type + ret_br wasm.LabelIndex + bp_idx wasm.LocalIndex = -1 // Base pointer temporary's index for function, if needed (-1 for none) + sp_global ?wasm.GlobalIndex + heap_base ?wasm.GlobalIndex + fn_local_idx_end int + fn_name string + stack_frame int // Size of the current stack frame, if needed + is_leaf_function bool = true + loop_breakpoint_stack []LoopBreakpoint + stack_top int // position in linear memory + data_base int // position in linear memory + needs_address bool + defer_vars []Var + is_direct_array_access bool // inside a `[direct_array_access]` function } -// Constants and globals -struct GlobalData { - init ast.Expr - ast_typ ast.Type - abs_address int // relative to `Gen.constant_data_offset` -} - -fn (gd GlobalData) to_var(name string) Global { - return Global{ - name: name - ast_typ: gd.ast_typ - abs_address: gd.abs_address - } -} - -struct StructInfo { +struct Global { mut: - offsets []int + init ?ast.Expr + v Var +} + +pub struct LoopBreakpoint { + c_continue wasm.LabelIndex + c_break wasm.LabelIndex + name string } pub fn (mut g Gen) v_error(s string, pos token.Pos) { @@ -96,78 +97,7 @@ pub fn (mut g Gen) w_error(s string) { util.verror('wasm error', s) } -fn (mut g Gen) vsp_leave() binaryen.Expression { - return binaryen.globalset(g.mod, c'__vsp', binaryen.localget(g.mod, g.bp_idx, type_i32)) -} - -fn (mut g Gen) setup_stack_frame(body binaryen.Expression) binaryen.Expression { - // The V WASM stack grows upwards. This is a choice that came - // to me after considering the following. - // - // 1. Store operator offsets cannot be negative. - // 2. The size allocated for the stack is unknown until - // the end of the function's generation. - // This means that stack deallocation code when returning - // early from function's do not know how much to free. - // 3. I came up with an alternative, a single exit point - // inside a function, with values "falling through" to the - // end of a function and being returned. - // This would fix problem 2. It did not work... - // https://github.com/WebAssembly/binaryen/issues/5490 - // - // Any other option would cause a large amount of boilerplate - // WASM code being duplicated at every return statement. - // - // stack_enter: - // global.get $__vsp - // local.tee $bp_idx - // i32.const {stack_frame} - // i32.add - // global.set $__vsp - // stack_leave: - // local.get $bp_idx - // global.set $__vsp - - // No stack allocations needed! - if g.stack_frame == 0 { - g.stack_patches.clear() - return body - } - g.needs_stack = true - - padded_stack_frame := round_up_to_multiple(g.stack_frame, 8) - - stack_enter := binaryen.globalset(g.mod, c'__vsp', binaryen.binary(g.mod, binaryen.addint32(), - binaryen.constant(g.mod, binaryen.literalint32(padded_stack_frame)), binaryen.localtee(g.mod, - g.bp_idx, binaryen.globalget(g.mod, c'__vsp', type_i32), type_i32))) - mut n_body := [stack_enter, body] - - if g.curr_ret[0] == ast.void_type { - n_body << g.vsp_leave() - } - - for bp in g.stack_patches { - // Insert stack leave on all return calls - binaryen.blockinsertchildat(bp.block, bp.idx, g.vsp_leave()) - } - g.stack_patches.clear() - - return g.mkblock(n_body) -} - -fn (mut g Gen) function_return_wasm_type(typ ast.Type) binaryen.Type { - if typ == ast.void_type { - return type_none - } - types := g.unpack_type(typ).filter(it.is_any_kind_of_pointer() - || g.table.sym(it).info !is ast.Struct).map(g.get_wasm_type(it)) - if types.len == 0 { - return type_none - } - return binaryen.typecreate(types.data, types.len) -} - -fn (g Gen) unpack_type(typ ast.Type) []ast.Type { +pub fn (g Gen) unpack_type(typ ast.Type) []ast.Type { ts := g.table.sym(typ) return match ts.info { ast.MultiReturn { @@ -179,57 +109,66 @@ fn (g Gen) unpack_type(typ ast.Type) []ast.Type { } } -fn (mut g Gen) fn_external_import(node ast.FnDecl) { +pub fn (g Gen) is_param_type(typ ast.Type) bool { + return !typ.is_ptr() && !g.is_pure_type(typ) +} + +pub fn (mut g Gen) dbg_type_name(name string, typ ast.Type) string { + return '${name}<${`&`.repeat(typ.nr_muls())}${*g.table.sym(typ)}>' +} + +pub fn unpack_literal_int(typ ast.Type) ast.Type { + return if typ == ast.int_literal_type { ast.i64_type } else { typ } +} + +pub fn (g &Gen) get_ns_plus_name(default_name string, attrs []ast.Attr) (string, string) { + mut name := default_name + mut namespace := 'env' + + if cattr := attrs.find_first('wasm_import_namespace') { + namespace = cattr.arg + } + if cattr := attrs.find_first('wasm_import_name') { + name = cattr.arg + } + + return namespace, name +} + +pub fn (mut g Gen) fn_external_import(node ast.FnDecl) { if !node.no_body || node.is_method { g.v_error('interop functions cannot have bodies', node.body_pos) } if node.language == .js && g.pref.os == .wasi { g.v_error('javascript interop functions are not allowed in a `wasi` build', node.pos) } + if node.return_type.has_flag(.option) || node.return_type.has_flag(.result) { + g.v_error('interop functions must not return option or result', node.pos) + } - mut paraml := []binaryen.Type{cap: node.params.len} + mut paraml := []wasm.ValType{cap: node.params.len} + mut retl := []wasm.ValType{cap: 1} for arg in node.params { if !g.is_pure_type(arg.typ) { - g.v_error('arguments to interop functions must be numbers, pointers or booleans', - arg.type_pos) + g.v_error('interop functions do not support complex arguments', arg.type_pos) } paraml << g.get_wasm_type(arg.typ) } - if !(node.return_type == ast.void_type || g.is_pure_type(node.return_type)) { - g.v_error('interop functions must return numbers, pointers or booleans', node.return_type_pos) + + is_ret := node.return_type != ast.void_type + + if is_ret && !g.is_pure_type(node.return_type) { + g.v_error('interop functions do not support complex returns', node.return_type_pos) } - return_type := g.get_wasm_type(node.return_type) - - // internal name: `JS.setpixel` - // external name: `setpixel` - binaryen.addfunctionimport(g.mod, node.name.str, g.module_import_namespace.str, node.short_name.str, - binaryen.typecreate(paraml.data, paraml.len), return_type) -} - -fn (mut g Gen) bare_function_start() { - g.bp_idx = g.new_local_temporary_anon(ast.int_type) - g.stack_frame = 0 -} - -fn (mut g Gen) bare_function(name string, expr binaryen.Expression) binaryen.Function { - mut temporaries := []binaryen.Type{cap: g.local_temporaries.len} - for idx := 0; idx < g.local_temporaries.len; idx++ { - temporaries << g.local_temporaries[idx].typ + if is_ret { + retl << g.get_wasm_type(node.return_type) } - wasm_expr := g.setup_stack_frame(expr) - - func := binaryen.addfunction(g.mod, name.str, type_none, type_none, temporaries.data, - temporaries.len, wasm_expr) - - g.local_temporaries.clear() - g.local_addresses = map[string]Stack{} - assert g.for_labels.len == 0 - - return func + namespace, name := g.get_ns_plus_name(node.short_name, node.attrs) + g.mod.new_function_import(namespace, name, paraml, retl) } -fn (mut g Gen) fn_decl(node ast.FnDecl) { +pub fn (mut g Gen) fn_decl(node ast.FnDecl) { if node.language in [.js, .wasm] { g.fn_external_import(node) return @@ -256,216 +195,353 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) { g.warning('fn_decl: ${name} is deprecated', node.pos) } - // The first parameter is an address of returned struct, - // regardless if the struct contains one field. - // (this should change and is currently a TODO to simplify generation) + mut paramdbg := []?string{cap: node.params.len} + mut paraml := []wasm.ValType{cap: node.params.len} + mut retl := []wasm.ValType{cap: 1} + + // fn ()! | fn () &IError + // fn () ?(...) | fn () (..., bool) + // fn () !(...) | fn () (..., &IError) // - // All structs are passed by reference regardless if the struct contains one field. - // (todo again...) - // - // Multi returns are implemented with a binaryen tuple type, not a struct reference. + // fn (...) struct | fn (_ &struct, ...) + // fn (...) !struct | fn (_ &struct, ...) &IError + // fn (...) (...struct) | fn (...&struct, ...) - return_type := g.function_return_wasm_type(node.return_type) - - mut paraml := []binaryen.Type{cap: node.params.len + 1} - g.bp_idx = -1 - g.stack_frame = 0 - - g.curr_ret = g.unpack_type(node.return_type) - - for idx, typ in g.curr_ret { - sym := g.table.sym(typ) - if sym.info is ast.Struct && !typ.is_any_kind_of_pointer() { - g.local_temporaries << Temporary{ - name: '__return${idx}' - typ: type_i32 // pointer - ast_typ: typ - idx: g.local_temporaries.len + g.ret_rvars = []Var{} + rt := node.return_type + rts := g.table.sym(rt) + g.ret = rt + match rts.info { + ast.MultiReturn { + for t in rts.info.types { + wtyp := g.get_wasm_type(t) + if g.is_param_type(t) { + paramdbg << g.dbg_type_name('__rval(${g.ret_rvars.len})', t) + paraml << wtyp + g.ret_rvars << Var{ + typ: t + idx: g.ret_rvars.len + is_address: true + } + } else { + retl << wtyp + } + g.ret_types << t + } + if rt.has_flag(.option) { + g.v_error('option types are not implemented', node.return_type_pos) + retl << .i32_t // bool } - paraml << ast.voidptr_type } + else { + if rt.idx() != ast.void_type_idx { + wtyp := g.get_wasm_type(rt) + if g.is_param_type(rt) { + paramdbg << g.dbg_type_name('__rval(0)', rt) + paraml << wtyp + g.ret_rvars << Var{ + typ: rt + is_address: true + } + } else { + retl << wtyp + } + g.ret_types << rt + } else if rt.has_flag(.option) { + g.v_error('returning a void option is forbidden', node.return_type_pos) + } + } + } + if rt.has_flag(.result) { + g.v_error('result types are not implemented', node.return_type_pos) + retl << .i32_t // &IError } for p in node.params { - typ := g.get_wasm_type(p.typ) - /* - if g.table.sym(p.typ).info is ast.Struct { - println("INIT: ${g.structs}, ${g.table.sym(p.typ)}, ${g.table.sym(p.typ).idx}, ${p.typ}, ${p.typ.idx()}") - }*/ - g.local_temporaries << Temporary{ + typ := g.get_wasm_type_int_literal(p.typ) + ntyp := unpack_literal_int(p.typ) + g.local_vars << Var{ name: p.name - typ: typ - ast_typ: p.typ - idx: g.local_temporaries.len + typ: ntyp + idx: g.local_vars.len + g.ret_rvars.len + is_address: !g.is_pure_type(p.typ) } + paramdbg << g.dbg_type_name(p.name, p.typ) paraml << typ } - params_type := binaryen.typecreate(paraml.data, paraml.len) - g.bp_idx = g.new_local_temporary_anon(ast.int_type) - mut wasm_expr := g.expr_stmts(node.stmts, ast.void_type) - wasm_expr = g.setup_stack_frame(wasm_expr) + // bottom scope - mut temporaries := []binaryen.Type{cap: g.local_temporaries.len - paraml.len} - for idx := paraml.len; idx < g.local_temporaries.len; idx++ { - temporaries << g.local_temporaries[idx].typ + g.is_direct_array_access = node.is_direct_arr || g.pref.no_bounds_checking + g.fn_local_idx_end = (g.local_vars.len + g.ret_rvars.len) + g.fn_name = name + + mut should_export := g.pref.os == .browser && node.is_pub && node.mod == 'main' + + g.func = g.mod.new_debug_function(name, wasm.FuncType{paraml, retl, none}, paramdbg) + func_start := g.func.patch_pos() + if node.stmts.len > 0 { + g.ret_br = g.func.c_block([], retl) + { + g.expr_stmts(node.stmts, ast.void_type) + } + { + for idx, defer_stmt in node.defer_stmts { + g.get(g.defer_vars[idx]) + lbl := g.func.c_if([], []) + { + g.expr_stmts(defer_stmt.stmts, ast.void_type) + } + g.func.c_end(lbl) + } + } + g.func.c_end(g.ret_br) + g.bare_function_frame(func_start) } - - function := binaryen.addfunction(g.mod, name.str, params_type, return_type, temporaries.data, - temporaries.len, wasm_expr) - - mut export_name := name.str if cattr := node.attrs.find_first('export') { - export_name = cattr.arg.str - } - //&& g.pref.os == .browser - if node.is_pub && node.mod == 'main' { - binaryen.addfunctionexport(g.mod, name.str, export_name) - } - if g.pref.is_debug { - binaryen.functionsetdebuglocation(function, wasm_expr, g.file_path_idx, node.pos.line_nr, - node.pos.col) + g.func.export_name(cattr.arg) + should_export = true } + g.mod.commit(g.func, should_export) + g.bare_function_end() - if g.pref.printfn_list.len > 0 && name in g.pref.printfn_list { - binaryen.expressionprint(wasm_expr) - } - - // WTF?? map values are not resetting??? - // g.local_addresses.clear() - g.local_temporaries.clear() - g.local_addresses = map[string]Stack{} - assert g.for_labels.len == 0 + // printfn is not implemented! } -fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) binaryen.Expression { +pub fn (mut g Gen) bare_function_frame(func_start wasm.PatchPos) { + // Setup stack frame. + // If the function does not call other functions, + // a leaf function, the omission of setting the + // stack pointer is perfectly acceptable. + // + if g.stack_frame != 0 { + prolouge := g.func.patch_pos() + { + g.func.global_get(g.sp()) + g.func.i32_const(g.stack_frame) + g.func.sub(.i32_t) + if !g.is_leaf_function { + g.func.local_tee(g.bp()) + g.func.global_set(g.sp()) + } else { + g.func.local_set(g.bp()) + } + } + g.func.patch(func_start, prolouge) + if !g.is_leaf_function { + g.func.global_get(g.sp()) + g.func.i32_const(g.stack_frame) + g.func.add(.i32_t) + g.func.global_set(g.sp()) + } + } +} + +pub fn (mut g Gen) bare_function_end() { + g.local_vars.clear() + g.ret_rvars.clear() + g.ret_types.clear() + g.defer_vars.clear() + g.bp_idx = -1 + g.stack_frame = 0 + g.is_leaf_function = true + g.is_direct_array_access = false + assert g.loop_breakpoint_stack.len == 0 +} + +pub fn (mut g Gen) literalint(val i64, expected ast.Type) { + match g.get_wasm_type(expected) { + .i32_t { g.func.i32_const(val) } + .i64_t { g.func.i64_const(val) } + .f32_t { g.func.f32_const(f32(val)) } + .f64_t { g.func.f64_const(f64(val)) } + else { g.w_error('literalint: bad type `${expected}`') } + } +} + +pub fn (mut g Gen) literal(val string, expected ast.Type) { + match g.get_wasm_type(expected) { + .i32_t { g.func.i32_const(val.int()) } + .i64_t { g.func.i64_const(val.i64()) } + .f32_t { g.func.f32_const(val.f32()) } + .f64_t { g.func.f64_const(val.f64()) } + else { g.w_error('literal: bad type `${expected}`') } + } +} + +pub fn (mut g Gen) cast(typ ast.Type, expected_type ast.Type) { + wtyp := g.as_numtype(g.get_wasm_type_int_literal(typ)) + expected_wtype := g.as_numtype(g.get_wasm_type_int_literal(expected_type)) + + g.func.cast(wtyp, typ.is_signed(), expected_wtype) +} + +pub fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) { if expr is ast.IntegerLiteral { - return g.literal(expr.val, expected_type) + g.literal(expr.val, expected_type) + return } else if expr is ast.FloatLiteral { - return g.literal(expr.val, expected_type) + g.literal(expr.val, expected_type) + return } got_type := ast.mktyp(got_type_raw) - return g.cast_t(g.expr(expr, got_type), got_type, expected_type) + got_wtype := g.as_numtype(g.get_wasm_type(got_type)) + expected_wtype := g.as_numtype(g.get_wasm_type(expected_type)) + + g.expr(expr, got_type) + g.func.cast(got_wtype, got_type.is_signed(), expected_wtype) } -fn (mut g Gen) literalint(val i64, expected ast.Type) binaryen.Expression { - match g.get_wasm_type(expected) { - type_i32 { return binaryen.constant(g.mod, binaryen.literalint32(int(val))) } - type_i64 { return binaryen.constant(g.mod, binaryen.literalint64(val)) } - else {} - } - g.w_error('literalint: bad type `${*g.table.sym(expected)}`') -} - -fn (mut g Gen) literal(val string, expected ast.Type) binaryen.Expression { - match g.get_wasm_type(expected) { - type_i32 { return binaryen.constant(g.mod, binaryen.literalint32(val.int())) } - type_i64 { return binaryen.constant(g.mod, binaryen.literalint64(val.i64())) } - type_f32 { return binaryen.constant(g.mod, binaryen.literalfloat32(val.f32())) } - type_f64 { return binaryen.constant(g.mod, binaryen.literalfloat64(val.f64())) } - else {} - } - g.w_error('literal: bad type `${expected}`') -} - -fn (mut g Gen) handle_ptr_arithmetic(typ ast.Type, expr binaryen.Expression) binaryen.Expression { - return if typ.is_ptr() { - size, _ := g.get_type_size_align(typ) - binaryen.binary(g.mod, binaryen.mulint32(), expr, g.literalint(size, ast.voidptr_type)) - } else { - expr +pub fn (mut g Gen) handle_ptr_arithmetic(typ ast.Type) { + if typ.is_ptr() { + size, _ := g.pool.type_size(typ) + g.func.i32_const(size) + g.func.mul(.i32_t) } } -fn (mut g Gen) postfix_expr(node ast.PostfixExpr) binaryen.Expression { - kind := if node.op == .inc { token.Kind.plus } else { token.Kind.minus } - - var := g.get_var_from_expr(node.expr) - op := g.infix_from_typ(node.typ, kind) - - expr := binaryen.binary(g.mod, op, g.get_or_lea_lop(var, node.typ), g.handle_ptr_arithmetic(node.typ, - g.literal('0', node.typ))) - - return g.set_var(var, expr, ast_typ: node.typ) -} - -fn (mut g Gen) infix_expr(node ast.InfixExpr, expected ast.Type) binaryen.Expression { +pub fn (mut g Gen) infix_expr(node ast.InfixExpr, expected ast.Type) { if node.op in [.logical_or, .and] { - mut exprs := []binaryen.Expression{cap: 2} - - left := g.expr(node.left, node.left_type) - - temporary := g.new_local_temporary_anon(ast.bool_type) - exprs << binaryen.localset(g.mod, temporary, left) - - cmp := if node.op == .logical_or { - binaryen.unary(g.mod, binaryen.eqzint32(), binaryen.localget(g.mod, temporary, - type_i32)) - } else { - binaryen.localget(g.mod, temporary, type_i32) + temp := g.func.new_local_named(.i32_t, '__tmp') + { + g.expr(node.left, ast.bool_type) + g.func.local_set(temp) + } + g.func.local_get(temp) + if node.op == .logical_or { + g.func.eqz(.i32_t) } - exprs << binaryen.bif(g.mod, cmp, g.expr(node.right, node.right_type), binaryen.localget(g.mod, - temporary, type_i32)) - return g.mkblock(exprs) + blk := g.func.c_if([], [.i32_t]) + { + g.expr(node.right, ast.bool_type) + } + g.func.c_else(blk) + { + g.func.local_get(temp) + } + g.func.c_end(blk) + return } - op := g.infix_from_typ(node.left_type, node.op) + { + g.expr(node.left, node.left_type) + } + { + g.expr_with_cast(node.right, node.right_type, node.left_type) + if node.op in [.plus, .minus] && node.left_type.is_ptr() { + g.handle_ptr_arithmetic(node.left_type.deref()) + } + } + g.infix_from_typ(node.left_type, node.op) - infix := binaryen.binary(g.mod, op, g.expr(node.left, node.left_type), g.handle_ptr_arithmetic(node.left_type, - g.expr_with_cast(node.right, node.right_type, node.left_type))) - - res_typ := if infix_kind_return_bool(node.op) { + res_typ := if node.op in [.eq, .ne, .gt, .lt, .ge, .le] { ast.bool_type } else { node.left_type } - return g.cast_t(infix, res_typ, expected) + g.func.cast(g.as_numtype(g.get_wasm_type(res_typ)), res_typ.is_signed(), g.as_numtype(g.get_wasm_type(expected))) } -fn (mut g Gen) prefix_expr(node ast.PrefixExpr) binaryen.Expression { - expr := g.expr(node.right, node.right_type) +pub fn (mut g Gen) wasm_builtin(name string, node ast.CallExpr) { + for idx, arg in node.args { + g.expr(arg.expr, node.expected_arg_types[idx]) + } - return match node.op { + match name { + '__memory_grow' { + g.func.memory_grow() + } + '__memory_fill' { + g.func.memory_fill() + } + '__memory_copy' { + g.func.memory_copy() + } + '__memory_size' { + g.func.memory_size() + } + '__heap_base' { + if hp := g.heap_base { + g.func.global_get(hp) + } + hp := g.mod.new_global('__heap_base', false, .i32_t, false, wasm.constexpr_value(0)) + g.func.global_get(hp) + g.heap_base = hp + } + '__reinterpret_f32_u32' { + g.func.reinterpret(.f32_t) + } + '__reinterpret_u32_f32' { + g.func.reinterpret(.i32_t) + } + '__reinterpret_f64_u64' { + g.func.reinterpret(.f64_t) + } + '__reinterpret_u64_f64' { + g.func.reinterpret(.i64_t) + } + else { + panic('unreachable') + } + } +} + +pub fn (mut g Gen) prefix_expr(node ast.PrefixExpr, expected ast.Type) { + match node.op { .minus { if node.right_type.is_pure_float() { + g.expr(node.right, node.right_type) if node.right_type == ast.f32_type_idx { - binaryen.unary(g.mod, binaryen.negfloat32(), expr) + g.func.neg(.f32_t) } else { - binaryen.unary(g.mod, binaryen.negfloat64(), expr) + g.func.neg(.f64_t) } } else { // -val == 0 - val - if g.get_wasm_type(node.right_type) == type_i32 { - binaryen.binary(g.mod, binaryen.subint32(), binaryen.constant(g.mod, - binaryen.literalint32(0)), expr) - } else { - binaryen.binary(g.mod, binaryen.subint64(), binaryen.constant(g.mod, - binaryen.literalint64(0)), expr) - } + vt := g.get_wasm_type(node.right_type) + + g.literalint(0, node.right_type) + g.expr(node.right, node.right_type) + g.func.sub(g.as_numtype(vt)) } } .not { - binaryen.unary(g.mod, binaryen.eqzint32(), expr) + g.expr(node.right, node.right_type) + g.func.eqz(.i32_t) // !expr } .bit_not { // ~val == val ^ -1 - if g.get_wasm_type(node.right_type) == type_i32 { - binaryen.binary(g.mod, binaryen.xorint32(), expr, binaryen.constant(g.mod, - binaryen.literalint32(-1))) - } else { - binaryen.binary(g.mod, binaryen.xorint64(), expr, binaryen.constant(g.mod, - binaryen.literalint64(-1))) - } + vt := g.get_wasm_type(node.right_type) + + g.expr(node.right, node.right_type) + g.literalint(-1, node.right_type) + g.func.b_xor(g.as_numtype(vt)) } .amp { - g.lea_var_from_expr(node.right) + if v := g.get_var_from_expr(node.right) { + if !v.is_address { + g.v_error("cannot take the address of a value that doesn't live on the stack", + node.pos) + } + g.ref(v) + } else { + g.needs_address = true + { + g.expr(node.right, node.right_type) + } + g.needs_address = false + } } .mul { - g.deref(expr, node.right_type) + g.expr(node.right, node.right_type) + if g.is_pure_type(expected) && !g.needs_address { + // in a RHS context, not lvalue + g.load(expected, 0) + } } else { // impl deref (.mul), and impl address of (.amp) @@ -474,205 +550,338 @@ fn (mut g Gen) prefix_expr(node ast.PrefixExpr) binaryen.Expression { } } -fn (mut g Gen) mknblock(name string, nodes []binaryen.Expression) binaryen.Expression { - if nodes.len == 0 { - return binaryen.nop(g.mod) - } - - g.lbl++ - return binaryen.block(g.mod, '${name}${g.lbl}'.str, nodes.data, nodes.len, type_auto) -} - -fn (mut g Gen) mkblock(nodes []binaryen.Expression) binaryen.Expression { - if nodes.len == 0 { - return binaryen.nop(g.mod) - } - - g.lbl++ - return binaryen.block(g.mod, 'BLK${g.lbl}'.str, nodes.data, nodes.len, type_auto) -} - -fn (mut g Gen) if_branch(ifexpr ast.IfExpr, idx int) binaryen.Expression { +pub fn (mut g Gen) if_branch(ifexpr ast.IfExpr, expected ast.Type, unpacked_params []wasm.ValType, idx int, existing_rvars []Var) { curr := ifexpr.branches[idx] - next := if ifexpr.has_else && idx + 2 >= ifexpr.branches.len { - g.expr_stmts(ifexpr.branches[idx + 1].stmts, ifexpr.typ) - } else if idx + 1 >= ifexpr.branches.len { - unsafe { nil } + g.expr(curr.cond, ast.bool_type) + blk := g.func.c_if([], unpacked_params) + { + g.rvar_expr_stmts(curr.stmts, expected, existing_rvars) + } + { + if ifexpr.has_else && idx + 2 >= ifexpr.branches.len { + g.func.c_else(blk) + g.rvar_expr_stmts(ifexpr.branches[idx + 1].stmts, expected, existing_rvars) + } else if !(idx + 1 >= ifexpr.branches.len) { + g.func.c_else(blk) + g.if_branch(ifexpr, expected, unpacked_params, idx + 1, existing_rvars) + } + } + g.func.c_end(blk) +} + +pub fn (mut g Gen) if_expr(ifexpr ast.IfExpr, expected ast.Type, existing_rvars []Var) { + params := if expected == ast.void_type { + []wasm.ValType{} + } else if existing_rvars.len == 0 { + g.unpack_type(expected).map(g.get_wasm_type(it)) } else { - g.if_branch(ifexpr, idx + 1) + g.unpack_type(expected).filter(!g.is_param_type(it)).map(g.get_wasm_type(it)) } - return binaryen.bif(g.mod, g.expr(curr.cond, ast.bool_type), g.expr_stmts(curr.stmts, - ifexpr.typ), next) + g.if_branch(ifexpr, expected, params, 0, existing_rvars) } -fn (mut g Gen) if_expr(ifexpr ast.IfExpr) binaryen.Expression { - return g.if_branch(ifexpr, 0) -} +pub fn (mut g Gen) call_expr(node ast.CallExpr, expected ast.Type, existing_rvars []Var) { + mut wasm_ns := ?string(none) + mut name := node.name -const wasm_builtins = ['__memory_grow', '__memory_fill', '__memory_copy', '__memory_size', - '__heap_base'] + is_print := name in ['panic', 'println', 'print', 'eprintln', 'eprint'] -fn (mut g Gen) wasm_builtin(name string, node ast.CallExpr) binaryen.Expression { - mut args := []binaryen.Expression{cap: node.args.len} + if name in ['__memory_grow', '__memory_fill', '__memory_copy', '__memory_size', '__heap_base', + '__reinterpret_f32_u32', '__reinterpret_u32_f32', '__reinterpret_f64_u64', + '__reinterpret_u64_f64'] { + g.wasm_builtin(node.name, node) + return + } + + if node.is_method { + name = '${g.table.get_type_name(node.receiver_type)}.${node.name}' + } + + if node.language in [.js, .wasm] { + cfn_attrs := g.table.fns[node.name].attrs + + short_name := if node.language == .js { + node.name.all_after_last('JS.') + } else { + node.name.all_after_last('WASM.') + } + + // setting a `?string` in a multireturn causes UNDEFINED BEHAVIOR AND STACK CORRUPTION + // best to use a workaround till that is fixed + + mut wasm_ns_storage := '' + wasm_ns_storage, name = g.get_ns_plus_name(short_name, cfn_attrs) + wasm_ns = wasm_ns_storage + } + + // callconv: {return structs} {method self} {arguments} + + // {return structs} + // + mut rvars := existing_rvars.clone() + rts := g.unpack_type(node.return_type) + if rvars.len == 0 && node.return_type != ast.void_type { + for rt in rts { + if g.is_param_type(rt) { + v := g.new_local('', rt) + rvars << v + } + } + } + for v in rvars { + g.ref(v) + } + + // {method self} + // + if node.is_method { + expr := if !node.left_type.is_ptr() && node.receiver_type.is_ptr() { + ast.Expr(ast.PrefixExpr{ + op: .amp + right: node.left + }) + } else { + node.left + } + // hack alert! + if node.receiver_type == ast.int_literal_type && expr is ast.IntegerLiteral { + g.literal(expr.val, ast.i64_type) + } else { + g.expr(expr, node.receiver_type) + } + } + + // {arguments} + // for idx, arg in node.args { - args << g.expr(arg.expr, node.expected_arg_types[idx]) + mut expr := arg.expr + + mut typ := arg.typ + if is_print && typ != ast.string_type { + has_str, _, _ := g.table.sym(typ).str_method_info() + if typ != ast.string_type && !has_str { + g.v_error('cannot implicitly convert as argument does not have a .str() function', + arg.pos) + } + + expr = ast.CallExpr{ + name: 'str' + left: expr + left_type: typ + receiver_type: typ + return_type: ast.string_type + is_method: true + } + } + + // another hack alert! + if node.expected_arg_types[idx] == ast.int_literal_type && mut expr is ast.IntegerLiteral { + g.literal(expr.val, ast.i64_type) + } else { + g.expr(expr, node.expected_arg_types[idx]) + } } - match name { - '__memory_grow' { - return binaryen.memorygrow(g.mod, args[0], c'memory', false) - } - '__memory_fill' { - return binaryen.memoryfill(g.mod, args[0], args[1], args[2], c'memory') - } - '__memory_copy' { - return binaryen.memorycopy(g.mod, args[0], args[1], args[2], c'memory', c'memory') - } - '__memory_size' { - return binaryen.memorysize(g.mod, c'memory', false) - } - '__heap_base' { - return binaryen.globalget(g.mod, c'__heap_base', type_i32) - } - else { - panic('unreachable') - } + if namespace := wasm_ns { + // import calls won't touch `__vsp` ! + + g.func.call_import(namespace, name) + } else { + // other calls may... + g.is_leaf_function = false + + g.func.call(name) } -} -[params] -struct AssignOpts { - op token.Kind = .assign -} + if expected == ast.void_type && node.return_type != ast.void_type { + for rt in rts { // order doesn't matter + if !g.is_param_type(rt) { + g.func.drop() + } + } + } else if rvars.len > 0 && existing_rvars.len == 0 { + mut rr_vars := []Var{cap: rts.len} + mut r := rvars.len -fn (mut g Gen) assign_expr_to_var(address LocalOrPointer, right ast.Expr, expected ast.Type, cfg AssignOpts) binaryen.Expression { - return match right { - ast.StructInit { - if cfg.op !in [.decl_assign, .assign] { - op := token.assign_op_to_infix_op(cfg.op) - name := '${g.table.get_type_name(expected)}.${op}' - - // args: [&return, &left, &right] - args := [g.get_or_lea_lop(address, expected), - g.get_or_lea_lop(address, expected), g.expr(right, expected)] - - binaryen.call(g.mod, name.str, args.data, args.len, type_none) + for rt in rts.reverse() { + if !g.is_param_type(rt) { + v := g.new_local('', rt) + rr_vars << v + g.set(v) } else { - g.init_struct(address as Var, right) + r-- + rr_vars << rvars[r] } } - ast.StringLiteral { - if g.table.sym(expected).info !is ast.Struct { - offset, _ := g.allocate_string(right) - return g.set_var(address as Var, g.literalint(offset, ast.int_type)) - } - var := (address as Var) as Stack - - offset, len := g.allocate_string(right) - - g.mknblock('STRINGINIT', [ - g.set_var_v(Stack{ address: var.address, ast_typ: ast.charptr_type }, - g.literalint(offset, ast.u32_type), - offset: 0 - ), - g.set_var_v(Stack{ address: var.address, ast_typ: ast.int_type }, g.literalint(len, - ast.int_type), - offset: g.table.pointer_size - ), - ]) - } - ast.ArrayInit { - var := (address as Var) as Stack - mut exprs := []binaryen.Expression{} - - if !right.is_fixed { - g.w_error('wasm backend does not support non fixed arrays yet') - } - elm_typ := right.elem_type - elm_size, _ := g.get_type_size_align(elm_typ) - mut offset := 0 - if !right.has_val { - return g.mknblock('ARRAYINIT(ZERO)', [ - g.zero_fill(right.typ, var.address), - ]) - } - // [10, 15]! - for e in right.exprs { - exprs << g.assign_expr_to_var(Var(Stack{ - address: var.address + offset - ast_typ: elm_typ - }), e, elm_typ) - offset += elm_size - } - - g.mknblock('ARRAYINIT', exprs) - } - else { - initexpr := g.expr(right, expected) - - expr := if cfg.op !in [.decl_assign, .assign] { - if g.is_pure_type(expected) { - val := g.get_or_lea_lop(address, expected) - op := g.infix_from_typ(expected, token.assign_op_to_infix_op(cfg.op)) - - binaryen.binary(g.mod, op, val, initexpr) - } else { - g.w_error('arith unimplemented or unreachable for struct') - } - } else { - initexpr - } - g.set_var(address, expr, ast_typ: expected) + for v in rr_vars.reverse() { + g.get(v) } } + if node.is_noreturn { + g.func.unreachable() + } } -fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression { - return match node { +pub fn (mut g Gen) get_field_offset(typ ast.Type, name string) int { + ts := g.table.sym(typ) + field := ts.find_field(name) or { g.w_error('could not find field `${name}` on init') } + si := g.pool.type_struct_info(typ) or { panic('unreachable') } + return si.offsets[field.i] +} + +pub fn (mut g Gen) field_offset(typ ast.Type, name string) { + offset := g.get_field_offset(typ, name) + if offset != 0 { + g.func.i32_const(offset) + g.func.add(.i32_t) + } +} + +pub fn (mut g Gen) load_field(typ ast.Type, ftyp ast.Type, name string) { + offset := g.get_field_offset(typ, name) + g.load(ftyp, offset) +} + +pub fn (mut g Gen) store_field(typ ast.Type, ftyp ast.Type, name string) { + offset := g.get_field_offset(typ, name) + g.store(ftyp, offset) +} + +pub fn (mut g Gen) expr(node ast.Expr, expected ast.Type) { + match node { ast.ParExpr, ast.UnsafeExpr { g.expr(node.expr, expected) } ast.ArrayInit { - pos := g.allocate_local_var('_anonarray', node.typ) - expr := g.assign_expr_to_var(Var(Stack{ address: pos, ast_typ: node.typ }), - node, node.typ) - g.mknblock('EXPR(ARRAYINIT)', [expr, g.lea_address(pos)]) + v := g.new_local('', node.typ) + g.set_with_expr(node, v) + g.get(v) } ast.GoExpr { g.w_error('wasm backend does not support threads') } ast.IndexExpr { - // TODO: IMPLICIT BOUNDS CHECKING - /* - if !node.is_direct { - g.w_error('implicit bounds checks are not implemented, create one manually') - }*/ - - mut ptr := g.expr(node.left, ast.voidptr_type) - if node.left_type == ast.string_type { - ptr = g.deref(ptr, ast.voidptr_type) - } - - size, _ := g.get_type_size_align(expected) - index := g.expr(node.index, ast.int_type) + mut direct_array_access := g.is_direct_array_access || node.is_direct + mut tmp_voidptr_var := wasm.LocalIndex(-1) // ptr + index * size - new_ptr := binaryen.binary(g.mod, binaryen.addint32(), ptr, binaryen.binary(g.mod, - binaryen.mulint32(), index, g.literalint(size, ast.int_type))) + mut typ := node.left_type + ts := g.table.sym(typ) - g.deref(new_ptr, expected) - } - ast.SelectorExpr { - g.cast_t(g.get_or_lea_lop(g.get_var_from_expr(node), node.typ), node.typ, - expected) + g.expr(node.left, node.left_type) + if node.left_type == ast.string_type { + if !direct_array_access { + tmp_voidptr_var = g.func.new_local_named(.i32_t, '__tmp') + g.func.local_tee(tmp_voidptr_var) + } + + // be pedantic... + g.load_field(ast.string_type, ast.voidptr_type, 'str') + typ = ast.u8_type + } else if typ.is_ptr() { + typ = typ.deref() + direct_array_access = true + } else { + match ts.info { + ast.Array { + g.w_error('wasm backend does not support dynamic arrays') + } + ast.ArrayFixed { + typ = ts.info.elem_type + if node.index.is_pure_literal() { + // checker would have gotten this by now + direct_array_access = true + } + } + else { + g.w_error('ast.IndexExpr: unreachable') + } + } + } + + size, _ := g.pool.type_size(typ) + + g.expr(node.index, ast.int_type) + + if !direct_array_access { + g.is_leaf_function = false // calls panic() + + idx_temp := g.func.new_local_named(.i32_t, '__tmp') + g.func.local_tee(idx_temp) + + // .len + if node.left_type == ast.string_type { + g.func.local_get(tmp_voidptr_var) + g.load_field(ast.string_type, ast.int_type, 'len') + } else if ts.info is ast.ArrayFixed { + g.func.i32_const(ts.info.size) + } else { + panic('unreachable') + } + + g.func.ge(.i32_t, false) + // is_signed: false, negative numbers will be reinterpreted as > 2^31 and will also trigger false + blk := g.func.c_if([], []) + { + g.expr(ast.StringLiteral{ val: '${g.file_pos(node.pos)}: ${ast.Expr(node)}' }, + ast.string_type) + g.func.call('eprintln') + g.expr(ast.StringLiteral{ val: 'index out of range' }, ast.string_type) + g.func.call('panic') + } + g.func.c_end(blk) + + g.func.local_get(idx_temp) + } + + if size > 1 { + g.literalint(size, ast.int_type) + g.func.mul(.i32_t) + } + + g.func.add(.i32_t) + + if !g.is_pure_type(typ) { + return + } + + if !g.needs_address { + // ptr + g.load(typ, 0) + } + g.cast(typ, expected) } ast.StructInit { - pos := g.allocate_local_var('_anonstruct', node.typ) - expr := g.assign_expr_to_var(Var(Stack{ address: pos, ast_typ: node.typ }), - node, node.typ) - g.mknblock('EXPR(STRUCTINIT)', [expr, g.lea_address(pos)]) + v := g.new_local('', node.typ) + g.set_with_expr(node, v) + g.get(v) + } + ast.SelectorExpr { + if v := g.get_var_from_expr(node) { + if g.needs_address { + if !v.is_address { + g.v_error("cannot take the address of a value that doesn't live on the stack. this is a current limitation.", + node.pos) + } + g.ref(v) + } else { + g.get(v) + } + } else { + g.needs_address = true + { + g.expr(node.expr, node.typ) + } + g.needs_address = false + g.field_offset(node.expr_type, node.field_name) + if g.is_pure_type(node.typ) && !g.needs_address { + // expected to be a pointer + g.load(node.typ, 0) + } + } + g.cast(node.typ, expected) } ast.MatchExpr { g.w_error('wasm backend does not support match expressions yet') @@ -694,185 +903,85 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression { if !g.table.known_type_idx(node.typ) { g.v_error('unknown type `${*g.table.sym(node.typ)}`', node.pos) } - size, _ := g.table.type_size(node.typ) + size, _ := g.pool.type_size(node.typ) g.literalint(size, ast.u32_type) } ast.BoolLiteral { - val := if node.val { binaryen.literalint32(1) } else { binaryen.literalint32(0) } - binaryen.constant(g.mod, val) + g.func.i32_const(i32(node.val)) } ast.StringLiteral { - if g.table.sym(expected).info !is ast.Struct { - offset, _ := g.allocate_string(node) - return g.literalint(offset, ast.int_type) + if expected != ast.string_type { + val := serialise.eval_escape_codes(node) or { panic('unreachable') } + str_pos := g.pool.append_string(val) + + // c'str' + g.literalint(g.data_base + str_pos, ast.voidptr_type) + return } - pos := g.allocate_local_var('_anonstring', ast.string_type) - - expr := g.assign_expr_to_var(Var(Stack{ address: pos, ast_typ: ast.string_type }), - node, ast.string_type) - g.mknblock('EXPR(STRINGINIT)', [expr, g.lea_address(pos)]) + v := g.new_local('', ast.string_type) + g.set_with_expr(node, v) + g.get(v) } ast.InfixExpr { g.infix_expr(node, expected) } ast.PrefixExpr { - g.prefix_expr(node) + g.prefix_expr(node, expected) } ast.PostfixExpr { - g.postfix_expr(node) + kind := if node.op == .inc { token.Kind.plus } else { token.Kind.minus } + v := g.get_var_or_make_from_expr(node.expr, node.typ) + + g.set_prepare(v) + { + g.get(v) + g.literalint(1, node.typ) + g.handle_ptr_arithmetic(node.typ) + g.infix_from_typ(node.typ, kind) + } + g.set_set(v) } ast.CharLiteral { - rns := node.val.runes()[0] - g.literalint(rns, ast.u32_type) + rns := serialise.eval_escape_codes_raw(node.val) or { panic('unreachable') }.runes()[0] + g.func.i32_const(rns) } ast.Ident { - // TODO: only supports local identifiers, no path.expressions or global names - g.get_var_t(node, expected) + v := g.get_var_from_ident(node) + g.get(v) + g.cast(v.typ, expected) } ast.IntegerLiteral, ast.FloatLiteral { g.literal(node.val, expected) } ast.Nil { - g.literalint(0, expected) + g.func.i32_const(0) } ast.IfExpr { - if node.branches.len == 2 && node.is_expr { - left := g.expr_stmts(node.branches[0].stmts, expected) - right := g.expr_stmts(node.branches[1].stmts, expected) - binaryen.bselect(g.mod, g.expr(node.branches[0].cond, ast.bool_type_idx), - left, right, g.get_wasm_type(expected)) - } else { - g.if_expr(node) - } + g.if_expr(node, expected, []) } ast.CastExpr { - expr := g.expr(node.expr, node.expr_type) - - if node.typ == ast.bool_type { - panic('unreachable') + // don't want to handle ast.int_literal_type + if node.expr is ast.IntegerLiteral || node.expr is ast.FloatLiteral { + g.expr(node.expr, node.typ) + return } - /* - if node.typ == ast.bool_type { - // WebAssembly booleans use the `i32` type - // = 0 | is false - // > 0 | is truestyp_to_str_fn_name - // - // It's a checker error to cast to bool anyway... + g.expr(node.expr, node.expr_type) - bexpr := g.cast(expr, g.get_wasm_type(node.expr_type), g.is_signed(node.expr_type), - type_i32) - binaryen.bselect(g.mod, bexpr, binaryen.constant(g.mod, binaryen.literalint32(1)), binaryen.constant(g.mod, - binaryen.literalint32(0)), type_i32) - } else - */ - g.cast(expr, g.get_wasm_type(node.expr_type), g.is_signed(node.expr_type), - g.get_wasm_type(node.typ)) + // TODO: unbelievable colossal hack + mut typ := node.expr_type + if node.expr is ast.Ident { + v := g.get_var_from_ident(node.expr) + if g.is_param(v) && node.expr_type == ast.int_literal_type { + typ = ast.i64_type + } + } + + g.func.cast(g.as_numtype(g.get_wasm_type(typ)), typ.is_signed(), g.as_numtype(g.get_wasm_type(node.typ))) } ast.CallExpr { - mut name := node.name - mut arguments := []binaryen.Expression{cap: node.args.len + 1} - - fret := g.function_return_wasm_type(node.return_type) - is_print := name in ['panic', 'println', 'print', 'eprintln', 'eprint'] - - if name in wasm.wasm_builtins { - return g.wasm_builtin(node.name, node) - } - - if node.is_method { - name = '${g.table.get_type_name(node.receiver_type)}.${node.name}' - } - - ret_types := g.unpack_type(node.return_type) - structs := ret_types.filter(g.table.sym(it).info is ast.Struct - && !it.is_any_kind_of_pointer()) - mut structs_addrs := []int{cap: structs.len} - - // ABI: {return structs} {method `self`}, then {arguments} - for typ in structs { - pos := g.allocate_local_var('_anonstruct', typ) - structs_addrs << pos - arguments << g.lea_address(pos) - } - if node.is_method { - expr := if !node.left_type.is_ptr() && node.receiver_type.is_ptr() { - ast.Expr(ast.PrefixExpr{ - op: .amp - right: node.left - }) - } else { - node.left - } - arguments << g.expr(expr, node.receiver_type) - } - for idx, arg in node.args { - mut expr := arg.expr - typ := arg.typ - - if is_print && typ != ast.string_type { - has_str, _, _ := g.table.sym(typ).str_method_info() - if typ != ast.string_type && !has_str { - g.v_error('cannot implicitly convert as argument does not have a .str() function', - arg.pos) - } - - expr = ast.CallExpr{ - name: 'str' - left: expr - left_type: typ - receiver_type: typ - return_type: ast.string_type - is_method: true - } - } - arguments << g.expr(expr, node.expected_arg_types[idx]) - } - - mut call := binaryen.call(g.mod, name.str, arguments.data, arguments.len, - fret) - if structs.len != 0 { - mut temporary := 0 - // The function's return values contains structs and must be reordered - - if ret_types.len - structs.len != 0 { - temporary = g.new_local_temporary_anon_wtyp(fret) - call = binaryen.localset(g.mod, temporary, call) - } - mut exprs := []binaryen.Expression{} - - mut sidx := 0 - mut tidx := 0 - for typ in ret_types { - ts := g.table.sym(typ) - - if ts.info is ast.Struct { - exprs << g.lea_address(structs_addrs[tidx]) - tidx++ - } else { - exprs << binaryen.tupleextract(g.mod, binaryen.localget(g.mod, - temporary, fret), sidx) - sidx++ - } - } - - vexpr := if exprs.len != 1 { - binaryen.tuplemake(g.mod, exprs.data, exprs.len) - } else { - exprs[0] - } - - call = g.mkblock([call, vexpr]) - } - if expected == ast.void_type && node.return_type != ast.void_type { - call = binaryen.drop(g.mod, call) - } - if node.is_noreturn { - // `[noreturn]` functions cannot return values - call = g.mkblock([call, binaryen.unreachable(g.mod)]) - } - call + g.call_expr(node, expected, []) } else { g.w_error('wasm.expr(): unhandled node: ' + node.type_name()) @@ -880,246 +989,261 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression { } } -fn (mut g Gen) expr(node ast.Expr, expected ast.Type) binaryen.Expression { - expr := g.expr_impl(node, expected) - - return expr +pub fn (g &Gen) file_pos(pos token.Pos) string { + return '${g.file_path}:${pos.line_nr + 1}:${pos.col + 1}' } -fn (mut g Gen) multi_assign_stmt(node ast.AssignStmt) binaryen.Expression { - if node.has_cross_var { - g.w_error('complex assign statements are not implemented') - } - - // - // Expected to be a `a, b := multi_return()`. - // - - mut exprs := []binaryen.Expression{cap: node.left.len + 1} - - ret := (node.right[0] as ast.CallExpr).return_type - wret := g.get_wasm_type(ret) - temporary := g.new_local_temporary_anon(ret) - - // Set multi return function to temporary, then use `tuple.extract`. - exprs << binaryen.localset(g.mod, temporary, g.expr(node.right[0], 0)) - - for i := 0; i < node.left.len; i++ { - left := node.left[i] - typ := node.left_types[i] - // rtyp := node.right_types[i] - - if left is ast.Ident { - // `_ = expr` - if left.kind == .blank_ident { - continue - } - if node.op == .decl_assign { - g.new_local(left, typ) - } - } - var := g.get_var_from_expr(left) - popexpr := binaryen.tupleextract(g.mod, binaryen.localget(g.mod, temporary, wret), - i) - exprs << g.set_var(var, popexpr) - } - - return g.mkblock(exprs) -} - -fn (mut g Gen) new_for_label(node_label string) string { - g.lbl++ - label := if node_label != '' { - node_label - } else { - g.lbl.str() - } - g.for_labels << label - - return label -} - -fn (mut g Gen) pop_for_label() { - g.for_labels.pop() -} - -struct BlockPatch { -mut: - idx int - block binaryen.Expression -} - -fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) binaryen.Expression { - return match node { +pub fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) { + match node { ast.Block { g.expr_stmts(node.stmts, expected) } ast.Return { - mut leave_expr_list := []binaryen.Expression{cap: node.exprs.len} - mut exprs := []binaryen.Expression{cap: node.exprs.len} - for idx, expr in node.exprs { - typ := g.curr_ret[idx] - if g.table.sym(typ).info is ast.Struct && !typ.is_any_kind_of_pointer() { - // Could be adapted to use random pointers? - /* - if expr is ast.StructInit { - var := g.local_temporaries[g.get_local_temporary('__return${idx}')] - leave_expr_list << g.init_struct(var, expr) - }*/ - var := g.local_temporaries[g.get_local_temporary('__return${idx}')] - address := g.expr(expr, typ) - - leave_expr_list << g.blit(address, typ, binaryen.localget(g.mod, var.idx, - var.typ)) - } else { - exprs << g.expr(expr, typ) - } + if node.exprs.len > 1 { + g.set_with_multi_expr(ast.ConcatExpr{ vals: node.exprs }, g.ret, g.ret_rvars) + } else if node.exprs.len == 1 { + g.set_with_multi_expr(node.exprs[0], g.ret, g.ret_rvars) } - - mut patch := BlockPatch{ - idx: leave_expr_list.len - } - // leave_expr_list << g.vsp_leave() - - ret_expr := if exprs.len == 1 { - exprs[0] - } else if exprs.len == 0 { - unsafe { nil } - } else { - binaryen.tuplemake(g.mod, exprs.data, exprs.len) - } - leave_expr_list << binaryen.ret(g.mod, ret_expr) - - patch.block = g.mkblock(leave_expr_list) - g.stack_patches << patch - - patch.block + g.func.c_br(g.ret_br) } ast.ExprStmt { g.expr(node.expr, expected) } ast.ForStmt { - lbl := g.new_for_label(node.label) + block := g.func.c_block([], []) + { + loop := g.func.c_loop([], []) + { + g.loop_breakpoint_stack << LoopBreakpoint{ + c_continue: loop + c_break: block + name: node.label + } - lpp_name := 'L${lbl}' - blk_name := 'B${lbl}' - expr := if !node.is_inf { - // binaryen.bif(g.mod, g.expr(node.cond, ast.bool_type)) + if !node.is_inf { + g.expr(node.cond, ast.bool_type) + g.func.eqz(.i32_t) + g.func.c_br_if(block) // !cond, goto end + } + g.expr_stmts(node.stmts, ast.void_type) + g.func.c_br(loop) // goto loop - body := g.expr_stmts(node.stmts, ast.void_type) - lbody := [ - // If !condition, leave. - binaryen.br(g.mod, blk_name.str, binaryen.unary(g.mod, binaryen.eqzint32(), - g.expr(node.cond, ast.bool_type)), unsafe { nil }), - // Body. - body, - // Unconditional loop back to top. - binaryen.br(g.mod, lpp_name.str, unsafe { nil }, unsafe { nil }), - ] - loop := binaryen.loop(g.mod, lpp_name.str, g.mkblock(lbody)) - - binaryen.block(g.mod, blk_name.str, &loop, 1, type_none) - } else { - loop_top := binaryen.br(g.mod, lpp_name.str, unsafe { nil }, unsafe { nil }) - - loop := binaryen.loop(g.mod, lpp_name.str, g.mkblock([ - g.expr_stmts(node.stmts, ast.void_type), - loop_top, - ])) - - binaryen.block(g.mod, blk_name.str, &loop, 1, type_none) + g.loop_breakpoint_stack.pop() + } + g.func.c_end(loop) } - g.pop_for_label() - expr + g.func.c_end(block) } ast.ForCStmt { - mut for_stmt := []binaryen.Expression{} - if node.has_init { - for_stmt << g.expr_stmt(node.init, ast.void_type) + block := g.func.c_block([], []) + { + if node.has_init { + g.expr_stmt(node.init, ast.void_type) + } + + loop := g.func.c_loop([], []) + { + g.loop_breakpoint_stack << LoopBreakpoint{ + c_continue: loop + c_break: block + name: node.label + } + + if node.has_cond { + g.expr(node.cond, ast.bool_type) + g.func.eqz(.i32_t) + g.func.c_br_if(block) // !cond, goto end + } + + g.expr_stmts(node.stmts, ast.void_type) + + if node.has_inc { + g.expr_stmt(node.inc, ast.void_type) + } + + g.func.c_br(loop) + g.loop_breakpoint_stack.pop() + } + g.func.c_end(loop) } - - lbl := g.new_for_label(node.label) - lpp_name := 'L${lbl}' - blk_name := 'B${lbl}' - - mut loop_exprs := []binaryen.Expression{} - if node.has_cond { - condexpr := binaryen.unary(g.mod, binaryen.eqzint32(), g.expr(node.cond, - ast.bool_type)) - loop_exprs << binaryen.br(g.mod, blk_name.str, condexpr, unsafe { nil }) - } - loop_exprs << g.expr_stmts(node.stmts, ast.void_type) - - if node.has_inc { - loop_exprs << g.expr_stmt(node.inc, ast.void_type) - } - loop_exprs << binaryen.br(g.mod, lpp_name.str, unsafe { nil }, unsafe { nil }) - loop := binaryen.loop(g.mod, lpp_name.str, g.mkblock(loop_exprs)) - - for_stmt << binaryen.block(g.mod, blk_name.str, &loop, 1, type_none) - g.pop_for_label() - g.mkblock(for_stmt) + g.func.c_end(block) } ast.BranchStmt { - mut blabel := if node.label != '' { - node.label - } else { - g.for_labels[g.for_labels.len - 1] + mut bp := g.loop_breakpoint_stack.last() + if node.label != '' { + for i := g.loop_breakpoint_stack.len; i > 0; { + i-- + if g.loop_breakpoint_stack[i].name == node.label { + bp = g.loop_breakpoint_stack[i] + } + } } if node.kind == .key_break { - blabel = 'B${blabel}' + g.func.c_br(bp.c_break) } else { - blabel = 'L${blabel}' + g.func.c_br(bp.c_continue) } - binaryen.br(g.mod, blabel.str, unsafe { nil }, unsafe { nil }) + } + ast.DeferStmt { + v := g.new_local('__defer(${node.idx_in_fn})', ast.bool_type) + g.func.i32_const(1) + g.set(v) + g.defer_vars << v + } + ast.AssertStmt { + if !node.is_used { + return + } + + // calls builtin functions, don't want to corrupt stack frame! + g.is_leaf_function = false + + g.expr(node.expr, ast.bool_type) + g.func.eqz(.i32_t) // !expr + lbl := g.func.c_if([], []) + { + // main.main: ${msg} + // V panic: Assertion failed... + + mut msg := '${g.file_pos(node.pos)}: fn ${g.fn_name}: ${ast.Stmt(node)}' + if node.extra is ast.StringLiteral { + msg += ", '${node.extra.val}'" + } + + g.expr(ast.StringLiteral{ val: msg }, ast.string_type) + g.func.call('eprintln') + g.expr(ast.StringLiteral{ val: 'Assertion failed...' }, ast.string_type) + g.func.call('panic') + } + g.func.c_end(lbl) } ast.AssignStmt { - if (node.left.len > 1 && node.right.len == 1) || node.has_cross_var { + if node.has_cross_var { + g.w_error('complex assign statements are not implemented') + // `a, b = b, a` + } else { + // `a := 1` | `a, b := 1, 2` // `a, b := foo()` // `a, b := if cond { 1, 2 } else { 3, 4 }` - // `a, b = b, a` - g.multi_assign_stmt(node) - } else { - // `a := 1` | `a,b := 1,2` + is_expr_assign := node.op !in [.decl_assign, .assign] - mut exprs := []binaryen.Expression{cap: node.left.len} - for i, left in node.left { - right := node.right[i] + // similar code from `call_expr()` + // create variables or obtain them for use as rvals + mut rvars := []Var{cap: node.left_types.len} + for idx, rt in node.left_types { + left := node.left[idx] + + mut var := Var{} + mut passed := false + + if left is ast.Ident { + if left.kind == .blank_ident { + var = g.new_local('_', rt) + passed = true + } else if node.op == .decl_assign { + var = g.new_local(left.name, rt) + passed = true + } + } + + if !passed && node.op == .assign { + if v := g.get_var_from_expr(left) { + var = v + } + } + + if g.is_param_type(rt) { + rvars << var + } + } + + mut set := false + if node.right.len == 1 { + right := node.right[0] + match right { + ast.IfExpr { + params := node.left_types.filter(!g.is_param_type(it)).map(g.get_wasm_type(it)) + g.if_branch(right, right.typ, params, 0, rvars) + set = true + } + ast.CallExpr { + g.call_expr(right, 0, rvars) + set = true + } + else { + // : set = false + // execute below instead + } + } + } + + // will never be a multi expr + // assume len == 1 for left and right + if is_expr_assign { + left, right, typ := node.left[0], node.right[0], node.left_types[0] + + rop := token.assign_op_to_infix_op(node.op) + lhs := g.get_var_or_make_from_expr(left, typ) + + if !g.is_pure_type(lhs.typ) { + // main.struct.+ + name := '${g.table.get_type_name(lhs.typ)}.${rop}' + g.ref(lhs) + g.ref(lhs) + g.expr(right, lhs.typ) + g.func.call(name) + } else { + g.set_prepare(lhs) + { + g.get(lhs) + g.expr(right, lhs.typ) + g.infix_from_typ(lhs.typ, rop) + } + g.set_set(lhs) + } + + return + } + + // prepare variables using expr() + // if is an rvar, set it and ignore following + if !set { + assert node.left.len == node.right.len + mut ridx := 0 + for idx, right in node.right { + typ := node.left_types[idx] + if g.is_param_type(typ) { + g.set_with_expr(right, rvars[ridx]) + ridx++ + } else { + g.expr(right, typ) + } + } + } + + for i := node.left.len; i > 0; { + i-- + left := node.left[i] typ := node.left_types[i] - // `_ = expr` must be evaluated even if the value is being dropped! - // The optimiser would remove expressions without side effects. - - // a = expr - // b *= expr - // _ = expr - // a.b = expr - // *a = expr - // a[b] = expr + if g.is_param_type(typ) { + // is already set + continue + } if left is ast.Ident { // `_ = expr` if left.kind == .blank_ident { - exprs << binaryen.drop(g.mod, g.expr(right, typ)) + // expression still may have side effect + g.func.drop() continue } - if node.op == .decl_assign { - g.new_local(left, typ) - } } - var := g.get_var_from_expr(left) - exprs << g.assign_expr_to_var(var, right, typ, op: node.op) - } - - if exprs.len == 1 { - exprs[0] - } else if exprs.len != 0 { - g.mkblock(exprs) - } else { - binaryen.nop(g.mod) + v := g.get_var_or_make_from_expr(left, typ) + g.set(v) } } } @@ -1129,37 +1253,30 @@ fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) binaryen.Expression { } } -pub fn (mut g Gen) expr_stmts(stmts []ast.Stmt, expected ast.Type) binaryen.Expression { - if stmts.len == 0 { - return binaryen.nop(g.mod) - } - if stmts.len == 1 { - return g.expr_stmt(stmts[0], expected) - } - mut exprl := []binaryen.Expression{cap: stmts.len} - for idx, stmt in stmts { - rtyp := if idx + 1 == stmts.len { - expected - } else { - ast.void_type - } - exprl << g.expr_stmt(stmt, rtyp) - } - return g.mkblock(exprl) +pub fn (mut g Gen) expr_stmts(stmts []ast.Stmt, expected ast.Type) { + g.rvar_expr_stmts(stmts, expected, []) } -fn (mut g Gen) toplevel_stmt(node ast.Stmt) { +pub fn (mut g Gen) rvar_expr_stmts(stmts []ast.Stmt, expected ast.Type, existing_rvars []Var) { + for idx, stmt in stmts { + if idx + 1 >= stmts.len { + if stmt is ast.ExprStmt { + g.set_with_multi_expr(stmt.expr, expected, existing_rvars) + } else { + g.expr_stmt(stmt, expected) + } + } else { + g.expr_stmt(stmt, ast.void_type) + } + } +} + +pub fn (mut g Gen) toplevel_stmt(node ast.Stmt) { match node { ast.FnDecl { g.fn_decl(node) } - ast.Module { - if ns := node.attrs.find_first('wasm_import_namespace') { - g.module_import_namespace = ns.arg - } else { - g.module_import_namespace = 'env' - } - } + ast.Module {} ast.GlobalDecl {} ast.ConstDecl {} ast.Import {} @@ -1204,64 +1321,83 @@ pub fn (mut g Gen) calculate_enum_fields() { } pub fn gen(files []&ast.File, table &ast.Table, out_name string, w_pref &pref.Preferences) { + stack_top := 1024 + (16 * 1024) mut g := &Gen{ table: table pref: w_pref files: files eval: eval.new_eval(table, w_pref) - mod: binaryen.modulecreate() + pool: serialise.new_pool(table, store_relocs: true, null_terminated: false) + stack_top: stack_top + data_base: calc_align(stack_top + 1, 16) } g.table.pointer_size = 4 - binaryen.modulesetfeatures(g.mod, binaryen.featureall()) - binaryen.setlowmemoryunused(true) // Low 1KiB of memory is unused. - defer { - binaryen.moduledispose(g.mod) - } + g.mod.assign_memory('memory', true, 1, none) - if g.pref.os == .browser { - eprintln('`-os browser` is experimental and will not live up to expectations...') + if g.pref.is_debug { + g.mod.enable_debug(none) } g.calculate_enum_fields() for file in g.files { g.file_path = file.path - if g.pref.is_debug { - g.file_path_idx = binaryen.moduleadddebuginfofilename(g.mod, g.file_path.str) - } if file.errors.len > 0 { util.verror('wasm error', file.errors[0].str()) } g.toplevel_stmts(file.stmts) } - if g.globals.len != 0 { - g.needs_stack = true - } g.housekeeping() - mut valid := binaryen.modulevalidate(g.mod) - if valid { - binaryen.setdebuginfo(w_pref.is_debug) - if w_pref.is_prod { - binaryen.setoptimizelevel(3) - binaryen.moduleoptimize(g.mod) - } - } + mod := g.mod.compile() if out_name == '-' { - if g.pref.is_verbose { - binaryen.moduleprint(g.mod) + if os.is_atty(1) == 1 { + eprintln('pretty printing to stdout is not implemented for the time being') + eprintln('raw bytes can mess up your terminal, are you piping into a file?') + exit(1) } else { - binaryen.moduleprintstackir(g.mod, w_pref.is_prod) + print(mod.bytestr()) } } - if !valid { - g.w_error('validation failed, this should not happen. report an issue with the above messages') - } - if out_name != '-' { - bytes := binaryen.moduleallocateandwrite(g.mod, unsafe { nil }) - str := unsafe { (&char(bytes.binary)).vstring_with_len(int(bytes.binaryBytes)) } - os.write_file(out_name, str) or { panic(err) } + os.write_file_array(out_name, mod) or { panic(err) } + if g.pref.wasm_validate { + exe := $if windows { 'wasm-validate.exe' } $else { 'wasm-validate' } + if rt := os.find_abs_path_of_executable(exe) { + mut p := os.new_process(rt) + p.set_args([out_name]) + p.set_redirect_stdio() + p.run() + err := p.stderr_slurp() + p.wait() + if p.code != 0 { + eprintln(err) + g.w_error('validation failed, this should not happen. report an issue with the above messages, the webassembly generated, and appropriate code.') + } + } else { + g.w_error('${exe} not found! Try installing WABT (WebAssembly Binary Toolkit). Run `./cmd/tools/install_wabt.vsh`, to download a prebuilt executable for your platform.') + } + } + if g.pref.is_prod { + exe := $if windows { 'wasm-opt.exe' } $else { 'wasm-opt' } + if rt := os.find_abs_path_of_executable(exe) { + // -lmu: low memory unused, very important optimisation + res := os.execute('${os.quoted_path(rt)} -all -lmu -c -O4 ${os.quoted_path(out_name)} -o ${os.quoted_path(out_name)}') + if res.exit_code != 0 { + eprintln(res.output) + g.w_error('${rt} failed, this should not happen. Report an issue with the above messages, the webassembly generated, and appropriate code.') + } + } else { + g.w_error('${exe} not found! Try installing Binaryen. + | Run `./cmd/tools/install_binaryen.vsh`, to download a prebuilt executable for your platform. + | After that, either copy or symlink thirdparty/binaryen/bin/wasm-opt to a folder on your PATH, + | or add thirdparty/binaryen/bin to your PATH. + | Use `wasm-opt --version` to verify that it can be found. + '.strip_margin()) + } + } + } else if g.pref.wasm_validate || g.pref.is_prod { + eprintln('stdout output, cannot validate or optimise wasm') } } diff --git a/vlib/v/gen/wasm/mem.v b/vlib/v/gen/wasm/mem.v index 7efe3dc820..e5bf11551c 100644 --- a/vlib/v/gen/wasm/mem.v +++ b/vlib/v/gen/wasm/mem.v @@ -1,103 +1,62 @@ +// Copyright (c) 2023 l-m.dev. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. module wasm +import wasm import v.ast -import v.gen.wasm.binaryen -import strconv +import v.gen.wasm.serialise +import encoding.binary -type Var = Global | Stack | Temporary | ast.Ident - -fn (v Var) ast_typ() int { - if v is Temporary { - return v.ast_typ - } - if v is Stack { - return v.ast_typ - } - if v is Global { - return v.ast_typ - } - panic('unreachable') +pub struct Var { + name string +mut: + typ ast.Type + idx wasm.LocalIndex + is_address bool + is_global bool + g_idx wasm.GlobalIndex + offset int } -fn (v Var) address() int { - return (v as Stack).address -} - -struct Temporary { - name string - typ binaryen.Type - ast_typ ast.Type - // - idx int -} - -struct Stack { - name string - ast_typ ast.Type - // - address int -} - -struct Global { - name string - ast_typ ast.Type - // - abs_address int -} - -fn (g Gen) is_pure_type(typ ast.Type) bool { - if typ.is_pure_int() || typ.is_pure_float() || typ == ast.char_type_idx - || typ.is_any_kind_of_pointer() || typ.is_bool() { - return true - } - ts := g.table.sym(typ) - if ts.info is ast.Alias { - return g.is_pure_type(ts.info.parent_type) - } - return false -} - -fn (mut g Gen) new_global_const(obj ast.ScopeObject) { - obj_expr := match obj { - ast.ConstField { obj.expr } - ast.GlobalField { obj.expr } - else { panic('unreachable') } - } - typ := ast.mktyp(obj.typ) - - size, align := g.get_type_size_align(typ) - padding := (align - g.constant_data_offset % align) % align - g.globals[obj.name] = GlobalData{ - init: obj_expr - ast_typ: typ - abs_address: g.constant_data_offset - } - g.constant_data_offset += size + padding -} - -fn (mut g Gen) get_var_from_ident(ident ast.Ident) Var { +pub fn (mut g Gen) get_var_from_ident(ident ast.Ident) Var { mut obj := ident.obj if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] { obj = ident.scope.find(ident.name) or { g.w_error('unknown variable ${ident.name}') } } + match mut obj { ast.Var { - if obj.name !in g.local_addresses { - return g.local_temporaries[g.get_local_temporary(obj.name)] + if g.local_vars.len == 0 { + g.w_error('get_var_from_ident: g.local_vars.len == 0') } - return g.local_addresses[obj.name] + mut c := g.local_vars.len + for { + c-- + if g.local_vars[c].name == obj.name { + return g.local_vars[c] + } + if c == 0 { + break + } + } + g.w_error('get_var_from_ident: unreachable, variable not found') } ast.ConstField { - if obj.name !in g.globals { - g.new_global_const(obj) + if gbl := g.global_vars[obj.name] { + return gbl.v } - return g.globals[obj.name].to_var(obj.name) + gbl := g.new_global(obj.name, obj.typ, obj.expr, false) + g.global_vars[obj.name] = gbl + return gbl.v } ast.GlobalField { - if obj.name !in g.globals { - g.new_global_const(obj) + if gbl := g.global_vars[obj.name] { + return gbl.v } - return g.globals[obj.name].to_var(obj.name) + gbl := g.new_global(obj.name, obj.typ, obj.expr, true) + g.global_vars[obj.name] = gbl + return gbl.v } else { g.w_error('unsupported variable type type:${obj} name:${ident.name}') @@ -105,644 +64,783 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) Var { } } -type LocalOrPointer = Var | binaryen.Expression - -fn (mut g Gen) get_or_lea_lop(lp LocalOrPointer, expected ast.Type) binaryen.Expression { - size, _ := g.table.type_size(expected) - - mut offset := 0 - mut parent_typ := expected - mut is_expr := false - - expr := match lp { - binaryen.Expression { - is_expr = true - lp - } - Var { - match lp { - Temporary { - parent_typ = lp.ast_typ - binaryen.localget(g.mod, lp.idx, g.get_wasm_type(expected)) - } - Stack { - parent_typ = lp.ast_typ - offset = lp.address - g.get_bp() - } - Global { - parent_typ = lp.ast_typ - is_expr = true - g.literalint(lp.abs_address, ast.int_type) - } - else { - panic('unreachable') - } - } - } - } - - if (!is_expr && parent_typ == expected) || !g.is_pure_type(expected) { - return expr - } - - return binaryen.load(g.mod, u32(size), g.is_signed(expected), u32(offset), 0, g.get_wasm_type(expected), - expr, c'memory') -} - -fn (mut g Gen) lea_lop(lp LocalOrPointer, expected ast.Type) binaryen.Expression { - expr := match lp { - binaryen.Expression { - lp - } - Var { - match lp { - Temporary { - binaryen.localget(g.mod, lp.idx, g.get_wasm_type(expected)) - } - Stack { - g.get_bp() - } - Global { - g.literalint(lp.abs_address, ast.int_type) - } - else { - panic('unreachable') - } - } - } - } - - return expr -} - -fn (mut g Gen) lea_var_from_expr(node ast.Expr) binaryen.Expression { - var := g.get_var_from_expr(node) - - return match var { - binaryen.Expression { - var - } - Var { - match var { - Temporary { - if g.is_pure_type(var.ast_typ) { - g.w_error('lea_var_from_expr: you cannot take the address of a pure temporary') - } - binaryen.localget(g.mod, var.idx, type_i32) - } - Stack { - g.lea_address(var.address) - } - Global { - g.literalint(var.abs_address, ast.int_type) - } - else { - panic('unreachable') - } - } - } - } -} - -fn (mut g Gen) local_or_pointer_add_offset(v Var, offset int) LocalOrPointer { - return match v { - Temporary { - binaryen.binary(g.mod, binaryen.addint32(), binaryen.localget(g.mod, v.idx, - type_i32), binaryen.constant(g.mod, binaryen.literalint32(offset))) - } - Stack { - Var(Stack{ - ...v - address: v.address + offset - }) - } - Global { - Var(Global{ - ...v - abs_address: v.abs_address + offset - }) - } +pub fn (mut g Gen) get_var_from_expr(node ast.Expr) ?Var { + match node { ast.Ident { - panic('unreachable') - } - } -} - -// TODO: return `Var | binaryen.Expression` -fn (mut g Gen) get_var_from_expr(node ast.Expr) LocalOrPointer { - return match node { - ast.Ident { - g.get_var_from_ident(node) + return g.get_var_from_ident(node) } ast.ParExpr { - g.get_var_from_expr(node.expr) + return g.get_var_from_expr(node.expr) } ast.SelectorExpr { - address := g.get_var_from_expr(node.expr) + mut addr := g.get_var_from_expr(node.expr) or { + // if place { + // g.field_offset(node.expr_type, node.field_name) + // } + return none + } + addr.is_address = true + offset := g.get_field_offset(node.expr_type, node.field_name) - - match address { - binaryen.Expression { - binaryen.binary(g.mod, binaryen.addint32(), address, binaryen.constant(g.mod, - binaryen.literalint32(offset))) - } - Var { - g.local_or_pointer_add_offset(address, offset) - } - } - } - ast.IndexExpr { - address := g.get_var_from_expr(node.left) - - ts := g.table.sym(node.left_type) - deref_type := if g.is_pure_type(node.left_type) { - node.left_type.set_nr_muls(node.left_type.nr_muls() - 1) - } else if ts.kind == .array_fixed { - (ts.info as ast.ArrayFixed).elem_type - } else { - node.left_type - } - size, _ := g.get_type_size_align(deref_type) - - index := g.expr(node.index, ast.int_type) - mut ptr_address := binaryen.Expression(0) - - if address is binaryen.Expression { - ptr_address = address - } - if address is Var { - ptr_address = g.get_var_t(address, ast.voidptr_type) - } - - // ptr + index * size - binaryen.binary(g.mod, binaryen.addint32(), ptr_address, binaryen.binary(g.mod, - binaryen.mulint32(), index, g.literalint(size, ast.int_type))) - } - ast.PrefixExpr { - g.lea_lop(g.get_var_from_expr(node.right), ast.voidptr_type) + return g.offset(addr, node.typ, offset) } else { - g.w_error('get_var_from_expr: unexpected `${node.type_name()}`') + // g.w_error('get_var_from_expr: unexpected `${node.type_name()}`') + return none } } } -fn (mut g Gen) get_local_temporary(name string) int { - if g.local_temporaries.len == 0 { - g.w_error('get_local: g.local_temporaries.len == 0') +// ONLY call this with the LHS of an assign, an lvalue +// use get_var_from_expr in all other cases +pub fn (mut g Gen) get_var_or_make_from_expr(node ast.Expr, typ ast.Type) Var { + if v := g.get_var_from_expr(node) { + return v } - mut c := g.local_temporaries.len - for { - c-- - if g.local_temporaries[c].name == name { - return c - } - if c == 0 { - break - } + + mut v := g.new_local('__tmp', ast.voidptr_type) + g.needs_address = true + { + g.set_with_expr(node, v) } - g.w_error("get_local: cannot get '${name}'") + g.needs_address = false + + v.typ = typ + v.is_address = true + + return v } -fn (mut g Gen) new_local_temporary_anon_wtyp(w_typ binaryen.Type) int { - ret := g.local_temporaries.len - g.local_temporaries << Temporary{ - name: '_' - typ: w_typ - idx: ret +pub fn (mut g Gen) bp() wasm.LocalIndex { + if g.bp_idx == -1 { + g.bp_idx = g.func.new_local_named(.i32_t, '__vbp') } - return ret + return g.bp_idx } -fn (mut g Gen) new_local_temporary_anon(typ ast.Type) int { - ret := g.local_temporaries.len - g.local_temporaries << Temporary{ - name: '_' - typ: g.get_wasm_type(typ) - ast_typ: typ - idx: ret +pub fn (mut g Gen) sp() wasm.GlobalIndex { + if sp := g.sp_global { + return sp } - return ret + // (64KiB - 1KiB) of stack space, grows downwards. + // Memory addresses from 0 to 1024 are forbidden. + g.sp_global = g.mod.new_global('__vsp', false, .i32_t, true, wasm.constexpr_value(0)) + return g.sp() } -fn (mut g Gen) new_local_temporary(name string, typ ast.Type) Temporary { - idx := g.local_temporaries.len - var := Temporary{ - name: name - typ: g.get_wasm_type(typ) - ast_typ: typ - idx: idx - } - g.local_temporaries << var - return var -} - -fn (mut g Gen) new_local(var ast.Ident, typ ast.Type) { - if g.is_pure_type(typ) { - g.new_local_temporary(var.name, typ) - return - } - +pub fn (mut g Gen) new_local(name string, typ_ ast.Type) Var { + mut typ := typ_ ts := g.table.sym(typ) + + match ts.info { + ast.Enum { + typ = ts.info.typ + } + ast.Alias { + typ = ts.info.parent_type + } + else {} + } + + is_address := !g.is_pure_type(typ) + wtyp := g.get_wasm_type(typ) + + mut v := Var{ + name: name + typ: typ + is_address: is_address + } + + if !is_address { + v.idx = g.func.new_local_named(wtyp, g.dbg_type_name(name, typ_)) + g.local_vars << v + return v + } + v.idx = g.bp() + + // allocate memory, then assign an offset + // match ts.info { ast.Struct, ast.ArrayFixed { - g.allocate_local_var(var.name, typ) - } - ast.Enum { - g.new_local_temporary(var.name, ts.info.typ) + size, align := g.pool.type_size(typ) + padding := calc_padding(g.stack_frame, align) + address := g.stack_frame + g.stack_frame += size + padding + + v.offset = address } else { g.w_error('new_local: type `${*ts}` (${ts.info.type_name()}) is not a supported local type') } } + g.local_vars << v + return v } -fn (mut g Gen) deref(expr binaryen.Expression, expected ast.Type) binaryen.Expression { - size, _ := g.get_type_size_align(expected) - return binaryen.load(g.mod, u32(size), g.is_signed(expected), 0, 0, g.get_wasm_type(expected), - expr, c'memory') -} - -fn (mut g Gen) get_field_offset(typ ast.Type, name string) int { - ts := g.table.sym(typ) - field := ts.find_field(name) or { g.w_error('could not find field `${name}` on init') } - if typ !in g.structs { - g.get_type_size_align(typ.idx()) - } - return g.structs[typ.idx()].offsets[field.i] -} - -fn (mut g Gen) get_type_size_align(typ ast.Type) (int, int) { - ts := g.table.sym(typ) - if ts.size != -1 && typ in g.structs { - return ts.size, ts.align - } - - if ts.info !is ast.Struct { - return g.table.type_size(typ) - } - - ti := ts.info as ast.Struct - - // Code borrowed from native, hope you don't mind! - - mut strc := StructInfo{} - mut size := 0 - mut align := 1 - for f in ti.fields { - f_size, f_align := g.table.type_size(f.typ) - if f_size == 0 { - strc.offsets << 0 - continue +pub fn (mut g Gen) literal_to_constant_expression(typ_ ast.Type, init ast.Expr) ?wasm.ConstExpression { + typ := ast.mktyp(typ_) + match init { + ast.BoolLiteral { + return wasm.constexpr_value(int(init.val)) } - padding := (f_align - size % f_align) % f_align - strc.offsets << size + padding - size += f_size + padding - if f_align > align { - align = f_align + ast.CharLiteral { + return wasm.constexpr_value(int(init.val.runes()[0])) } - } - size = (size + align - 1) / align * align - g.structs[typ.idx()] = strc - - mut ts_ := g.table.sym(typ) - ts_.size = size - ts_.align = align - - return size, align -} - -fn (mut g Gen) allocate_local_var(name string, typ ast.Type) int { - size, align := g.get_type_size_align(typ) - padding := (align - g.stack_frame % align) % align - address := g.stack_frame - g.stack_frame += size + padding - g.local_addresses[name] = Stack{ - name: name - ast_typ: typ - address: address - } - - return address -} - -fn (mut g Gen) get_bp() binaryen.Expression { - return binaryen.localget(g.mod, g.bp_idx, type_i32) -} - -fn (mut g Gen) lea_address(address int) binaryen.Expression { - return if address != 0 { - binaryen.binary(g.mod, binaryen.addint32(), g.get_bp(), binaryen.constant(g.mod, - binaryen.literalint32(address))) - } else { - g.get_bp() - } -} - -// Will automatcally cast value from `var` to `ast_type`, will ignore if struct value. -// TODO: When supporting base types on the stack, actually cast them. -fn (mut g Gen) get_var_t(var Var, ast_typ ast.Type) binaryen.Expression { - return match var { - ast.Ident { - g.get_var_t(g.get_var_from_ident(var), ast_typ) - } - Temporary { - expr := binaryen.localget(g.mod, var.idx, var.typ) - g.cast_t(expr, var.ast_typ, ast_typ) - } - Stack { - address := if var.address != 0 { - binaryen.binary(g.mod, binaryen.addint32(), g.get_bp(), binaryen.constant(g.mod, - binaryen.literalint32(var.address))) - } else { - g.get_bp() - } - - if g.is_pure_type(var.ast_typ) { - g.cast_t(g.deref(address, var.ast_typ), var.ast_typ, ast_typ) - } else { - address + ast.FloatLiteral { + if typ == ast.f32_type { + return wasm.constexpr_value(init.val.f32()) + } else if typ == ast.f64_type { + return wasm.constexpr_value(init.val.f64()) } } - Global { - address := g.literalint(var.abs_address, ast.int_type) - if g.is_pure_type(var.ast_typ) { - g.cast_t(g.deref(address, var.ast_typ), var.ast_typ, ast_typ) - } else { - address + ast.IntegerLiteral { + if !typ.is_pure_int() { + return none } - } - } -} - -[params] -struct SetConfig { - offset int - ast_typ ast.Type -} - -fn (mut g Gen) set_to_address(address_expr binaryen.Expression, expr binaryen.Expression, ast_typ ast.Type) binaryen.Expression { - return if !g.is_pure_type(ast_typ) { - // `expr` is pointer - g.blit(expr, ast_typ, address_expr) - } else { - size, _ := g.table.type_size(ast_typ) - binaryen.store(g.mod, u32(size), 0, 0, address_expr, expr, g.get_wasm_type(ast_typ), - c'memory') - } -} - -fn (mut g Gen) set_var_v(address Var, expr binaryen.Expression, cfg SetConfig) binaryen.Expression { - return g.set_var(address, expr, cfg) -} - -fn (mut g Gen) set_var(address LocalOrPointer, expr binaryen.Expression, cfg SetConfig) binaryen.Expression { - ast_typ := if cfg.ast_typ != 0 { - cfg.ast_typ - } else { - (address as Var).ast_typ() - } - match address { - binaryen.Expression { - return g.set_to_address(address, expr, ast_typ) - } - Var { - var := address - - return match var { - ast.Ident { - g.set_var(g.get_var_from_ident(var), expr, cfg) - } - Temporary { - binaryen.localset(g.mod, var.idx, expr) - } - Stack { - if !g.is_pure_type(ast_typ) { - // `expr` is pointer - g.blit_local(expr, ast_typ, var.address + cfg.offset) - } else { - size, _ := g.table.type_size(ast_typ) - // println("address: ${var.address}, offset: ${cfg.offset}") - binaryen.store(g.mod, u32(size), u32(var.address + cfg.offset), - 0, g.get_bp(), expr, g.get_wasm_type(ast_typ), c'memory') - } - } - Global { - address_expr := g.literalint(var.abs_address + cfg.offset, ast.int_type) - g.set_to_address(address_expr, expr, ast_typ) - } - } - } - } -} - -// zero out stack memory in known local `address`. -fn (mut g Gen) zero_fill(ast_typ ast.Type, address int) binaryen.Expression { - size, _ := g.get_type_size_align(ast_typ) - - if size <= 4 { - zero := g.literalint(0, ast.int_type) - return binaryen.store(g.mod, u32(size), u32(address), 0, g.get_bp(), zero, type_i32, - c'memory') - } else if size <= 8 { - zero := g.literalint(0, ast.i64_type) - return binaryen.store(g.mod, u32(size), u32(address), 0, g.get_bp(), zero, type_i64, - c'memory') - } - return binaryen.memoryfill(g.mod, g.lea_address(address), g.literalint(0, ast.int_type), - g.literalint(size, ast.int_type), c'memory') -} - -// `memcpy` from `ptr` to known local `address` in stack memory. -fn (mut g Gen) blit_local(ptr binaryen.Expression, ast_typ ast.Type, address int) binaryen.Expression { - size, _ := g.get_type_size_align(ast_typ) - return binaryen.memorycopy(g.mod, g.lea_address(address), ptr, binaryen.constant(g.mod, - binaryen.literalint32(size)), c'memory', c'memory') -} - -// `memcpy` from `ptr` to `dest` -fn (mut g Gen) blit(ptr binaryen.Expression, ast_typ ast.Type, dest binaryen.Expression) binaryen.Expression { - size, _ := g.get_type_size_align(ast_typ) - return binaryen.memorycopy(g.mod, dest, ptr, binaryen.constant(g.mod, binaryen.literalint32(size)), - c'memory', c'memory') -} - -fn (mut g Gen) init_struct(var Var, init ast.StructInit) binaryen.Expression { - match var { - ast.Ident { - return g.init_struct(g.get_var_from_ident(var), init) - } - Stack { - mut exprs := []binaryen.Expression{} - - ts := g.table.sym(var.ast_typ) - match ts.info { - ast.Struct { - if init.init_fields.len == 0 && !(ts.info.fields.any(it.has_default_expr)) { - // Struct definition contains no default initialisers - // AND struct init contains no set values. - return g.mknblock('STRUCTINIT(ZERO)', [ - g.zero_fill(var.ast_typ, var.address), - ]) - } - - for i, f in ts.info.fields { - field_to_be_set := init.init_fields.map(it.name).contains(f.name) - fts := g.table.sym(f.typ) - if !field_to_be_set { - g.get_type_size_align(var.ast_typ) - offset := g.structs[var.ast_typ.idx()].offsets[i] - if f.has_default_expr { - init_expr := g.expr(f.default_expr, f.typ) // or `unaliased_typ`? - exprs << g.set_var_v(var, init_expr, ast_typ: f.typ, offset: offset) - } else { - if fts.info is ast.Struct { - exprs << g.init_struct(Stack{ - address: var.address + offset - ast_typ: f.typ - }, ast.StructInit{}) - } else { - exprs << g.zero_fill(f.typ, var.address + offset) - } - } - // TODO: replace invocations of `set_var` with `assign_expr_to_var`? - } - } - } + t := g.get_wasm_type(typ) + match t { + .i32_t { return wasm.constexpr_value(init.val.int()) } + .i64_t { return wasm.constexpr_value(init.val.i64()) } else {} } + } + else {} + } + return none +} + +pub fn (mut g Gen) new_global(name string, typ_ ast.Type, init ast.Expr, is_global_mut bool) Global { + mut typ := typ_ + ts := g.table.sym(typ) + + match ts.info { + ast.Enum { + typ = ts.info.typ + } + ast.Alias { + typ = ts.info.parent_type + } + else {} + } + + mut is_mut := false + is_address := !g.is_pure_type(typ) + mut init_expr := ?ast.Expr(none) + + cexpr := if cexpr_v := g.literal_to_constant_expression(unpack_literal_int(typ), init) { + is_mut = is_global_mut + cexpr_v + } else { + // Isn't a literal ... + if is_address { + // ... allocate memory and append + pos, is_init := g.pool.append(init, typ) + if !is_init { + // ... AND wait for init in `_vinit` + init_expr = init + } + wasm.constexpr_value(g.data_base + pos) + } else { + // ... wait for init in `_vinit` + init_expr = init + is_mut = true + + t := g.get_wasm_type(typ) + wasm.constexpr_value_zero(t) + } + } + + mut glbl := Global{ + init: init_expr + v: Var{ + name: name + typ: typ + is_address: is_address + is_global: true + g_idx: g.mod.new_global(g.dbg_type_name(name, typ), false, g.get_wasm_type_int_literal(typ), + is_mut, cexpr) + } + } + + return glbl +} + +// is_pure_type(voidptr) == true +// is_pure_type(&Struct) == false +pub fn (g Gen) is_pure_type(typ ast.Type) bool { + if typ.is_pure_int() || typ.is_pure_float() || typ == ast.char_type_idx + || typ.is_any_kind_of_pointer() || typ.is_bool() { + return true + } + ts := g.table.sym(typ) + match ts.info { + ast.Alias { + return g.is_pure_type(ts.info.parent_type) + } + ast.Enum { + return g.is_pure_type(ts.info.typ) + } + else {} + } + return false +} + +pub fn log2(size int) int { + return match size { + 1 { 0 } + 2 { 1 } + 4 { 2 } + 8 { 3 } + else { panic('unreachable') } + } +} + +pub fn (mut g Gen) load(typ ast.Type, offset int) { + size, align := g.pool.type_size(typ) + wtyp := g.as_numtype(g.get_wasm_type(typ)) + + match size { + 1 { g.func.load8(wtyp, typ.is_signed(), log2(align), offset) } + 2 { g.func.load16(wtyp, typ.is_signed(), log2(align), offset) } + else { g.func.load(wtyp, log2(align), offset) } + } +} + +pub fn (mut g Gen) store(typ ast.Type, offset int) { + size, align := g.pool.type_size(typ) + wtyp := g.as_numtype(g.get_wasm_type(typ)) + + match size { + 1 { g.func.store8(wtyp, log2(align), offset) } + 2 { g.func.store16(wtyp, log2(align), offset) } + else { g.func.store(wtyp, log2(align), offset) } + } +} + +pub fn (mut g Gen) get(v Var) { + if v.is_global { + g.func.global_get(v.g_idx) + } else { + g.func.local_get(v.idx) + } + + if v.is_address && g.is_pure_type(v.typ) { + g.load(v.typ, v.offset) + } else if v.is_address && v.offset != 0 { + g.func.i32_const(v.offset) + g.func.add(.i32_t) + } +} + +pub fn (mut g Gen) mov(to Var, v Var) { + if !v.is_address || g.is_pure_type(v.typ) { + g.get(v) + g.cast(v.typ, to.typ) + g.set(to) + return + } + + size, _ := g.pool.type_size(v.typ) + + if size > 16 { + g.ref(to) + g.ref(v) + g.func.i32_const(size) + g.func.memory_copy() + return + } + + mut sz := size + mut oz := 0 + for sz > 0 { + g.ref_ignore_offset(to) + g.ref_ignore_offset(v) + if sz - 8 >= 0 { + g.load(ast.u64_type_idx, v.offset + oz) + g.store(ast.u64_type_idx, to.offset + oz) + sz -= 8 + oz += 8 + } else if sz - 4 >= 0 { + g.load(ast.u32_type_idx, v.offset + oz) + g.store(ast.u32_type_idx, to.offset + oz) + sz -= 4 + oz += 4 + } else if sz - 2 >= 0 { + g.load(ast.u16_type_idx, v.offset + oz) + g.store(ast.u16_type_idx, to.offset + oz) + sz -= 2 + oz += 2 + } else if sz - 1 >= 0 { + g.load(ast.u8_type_idx, v.offset + oz) + g.store(ast.u8_type_idx, to.offset + oz) + sz -= 1 + oz += 1 + } + } +} + +pub fn (mut g Gen) set_prepare(v Var) { + if !v.is_address { + return + } + + if g.is_pure_type(v.typ) { + if v.is_global { + g.func.global_get(v.g_idx) + } else { + g.func.local_get(v.idx) + } + return + } +} + +pub fn (mut g Gen) set_set(v Var) { + if !v.is_address { + if v.is_global { + g.func.global_set(v.g_idx) + } else { + g.func.local_set(v.idx) + } + return + } + + if g.is_pure_type(v.typ) { + g.store(v.typ, v.offset) + return + } + + from := Var{ + typ: v.typ + idx: g.func.new_local_named(.i32_t, '__tmp') + is_address: v.is_address + } + + g.func.local_set(from.idx) + g.mov(v, from) +} + +// set structures with pointer, memcpy +// set pointers with value, get local, store value +// set value, set local +// -- set works with a single value present on the stack beforehand +// -- not optimial for copying stack memory or shuffling structs +// -- use mov instead +pub fn (mut g Gen) set(v Var) { + if !v.is_address { + if v.is_global { + g.func.global_set(v.g_idx) + } else { + g.func.local_set(v.idx) + } + return + } + + if g.is_pure_type(v.typ) { + l := g.new_local('__tmp', v.typ) + g.func.local_set(l.idx) + + if v.is_global { + g.func.global_get(v.g_idx) + } else { + g.func.local_get(v.idx) + } + + g.func.local_get(l.idx) + + g.store(v.typ, v.offset) + return + } + + from := Var{ + typ: v.typ + idx: g.func.new_local_named(.i32_t, '__tmp') + is_address: v.is_address + } + + g.func.local_set(from.idx) + g.mov(v, from) +} + +pub fn (mut g Gen) ref(v Var) { + g.ref_ignore_offset(v) + + if v.offset != 0 { + g.func.i32_const(v.offset) + g.func.add(.i32_t) + } +} + +pub fn (mut g Gen) ref_ignore_offset(v Var) { + if !v.is_address { + panic('unreachable') + } + + if v.is_global { + g.func.global_get(v.g_idx) + } else { + g.func.local_get(v.idx) + } +} + +// creates a new pointer variable with the offset `offset` and type `typ` +pub fn (mut g Gen) offset(v Var, typ ast.Type, offset int) Var { + if !v.is_address { + panic('unreachable') + } + + nv := Var{ + ...v + typ: typ + offset: v.offset + offset + } + + return nv +} + +pub fn (mut g Gen) zero_fill(v Var, size int) { + assert size > 0 + + // TODO: support coalescing `zero_fill` calls together. + // maybe with some kind of context? + // + // ```v + // struct AA { + // a bool + // b int = 20 + // c int + // d int + // } + // ``` + // + // ```wast + // (i32.store8 + // (local.get $0) + // (i32.const 0) + // ) + // (i32.store offset=4 + // (i32.const 20) + // (local.get $0) + // ) ;; /- join these together. + // (i32.store offset=8 ;;-\ + // (local.get $0) ;; | + // (i32.const 0) ;; | + // ) ;; | + // (i32.store offset=12 ;; | + // (local.get $0) ;; | + // (i32.const 0) ;; | + // ) ;;-/ + // ``` + + if size > 16 { + g.ref(v) + g.func.i32_const(0) + g.func.i32_const(size) + g.func.memory_fill() + return + } + + mut sz := size + mut oz := 0 + for sz > 0 { + g.ref_ignore_offset(v) + if sz - 8 >= 0 { + g.func.i64_const(0) + g.store(ast.u64_type_idx, v.offset + oz) + sz -= 8 + oz += 8 + } else if sz - 4 >= 0 { + g.func.i32_const(0) + g.store(ast.u32_type_idx, v.offset + oz) + sz -= 4 + oz += 4 + } else if sz - 2 >= 0 { + g.func.i32_const(0) + g.store(ast.u16_type_idx, v.offset + oz) + sz -= 2 + oz += 2 + } else if sz - 1 >= 0 { + g.func.i32_const(0) + g.store(ast.u8_type_idx, v.offset + oz) + sz -= 1 + oz += 1 + } + } +} + +pub fn (g &Gen) is_param(v Var) bool { + if v.is_global { + return false + } + + return v.idx < g.fn_local_idx_end +} + +pub fn (mut g Gen) set_with_multi_expr(init ast.Expr, expected ast.Type, existing_rvars []Var) { + // misleading name: this doesn't really perform similar to `set_with_expr` + match init { + ast.ConcatExpr { + mut r := 0 + types := g.unpack_type(expected) + for idx, expr in init.vals { + typ := types[idx] + if g.is_param_type(typ) { + if rhs := g.get_var_from_expr(expr) { + g.mov(existing_rvars[r], rhs) + } else { + g.set_with_expr(expr, existing_rvars[r]) + } + r++ + } else { + g.expr(expr, typ) + } + } + } + ast.IfExpr { + g.if_expr(init, expected, existing_rvars) + } + ast.CallExpr { + g.call_expr(init, expected, existing_rvars) + } + else { + if existing_rvars.len > 1 { + g.w_error('wasm.set_with_multi_expr(): (existing_rvars.len > 1) node: ' + + init.type_name()) + } + + if existing_rvars.len == 1 && g.is_param_type(expected) { + if rhs := g.get_var_from_expr(init) { + g.mov(existing_rvars[0], rhs) + } else { + g.set_with_expr(init, existing_rvars[0]) + } + } else { + g.expr(init, expected) + } + } + } +} + +pub fn (mut g Gen) set_with_expr(init ast.Expr, v Var) { + match init { + ast.StructInit { + size, _ := g.pool.type_size(v.typ) + ts := g.table.sym(v.typ) + ts_info := ts.info as ast.Struct + si := g.pool.type_struct_info(v.typ) or { panic('unreachable') } + + if init.init_fields.len == 0 && !(ts_info.fields.any(it.has_default_expr)) { + // Struct definition contains no default initialisers + // AND struct init contains no set values. + g.zero_fill(v, size) + return + } + + for i, f in ts_info.fields { + field_to_be_set := init.init_fields.map(it.name).contains(f.name) + + if !field_to_be_set { + offset := si.offsets[i] + offset_var := g.offset(v, f.typ, offset) + + fsize, _ := g.pool.type_size(f.typ) + + if f.has_default_expr { + g.set_with_expr(f.default_expr, offset_var) + } else { + g.zero_fill(offset_var, fsize) + } + } + } for f in init.init_fields { field := ts.find_field(f.name) or { g.w_error('could not find field `${f.name}` on init') } - offset := g.structs[var.ast_typ.idx()].offsets[field.i] - initexpr := g.expr(f.expr, f.expected_type) - exprs << g.set_var_v(var, initexpr, ast_typ: f.expected_type, offset: offset) + offset := si.offsets[field.i] + offset_var := g.offset(v, f.expected_type, offset) + + g.set_with_expr(f.expr, offset_var) } - - return g.mknblock('STRUCTINIT', exprs) } - else {} - } - panic('unreachable') -} + ast.StringLiteral { + val := serialise.eval_escape_codes(init) or { panic('unreachable') } + str_pos := g.pool.append_string(val) -// From native, this should be taken out into `StringLiteral.eval_escape_codes()` -fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string { - if str_lit.is_raw { - return str_lit.val - } - - str := str_lit.val - mut buffer := []u8{} - - mut i := 0 - for i < str.len { - if str[i] != `\\` { - buffer << str[i] - i++ - continue - } - - // skip \ - i++ - match str[i] { - `\\`, `'`, `"` { - buffer << str[i] - i++ - } - `a`, `b`, `f` { - buffer << str[i] - u8(90) - i++ - } - `n` { - buffer << `\n` - i++ - } - `r` { - buffer << `\r` - i++ - } - `t` { - buffer << `\t` - i++ - } - `u` { - i++ - utf8 := strconv.parse_int(str[i..i + 4], 16, 16) or { - g.w_error('invalid \\u escape code (${str[i..i + 4]})') - 0 + if v.typ != ast.string_type { + // c'str' + g.set_prepare(v) + { + g.literalint(g.data_base + str_pos, ast.voidptr_type) } - i += 4 - buffer << u8(utf8) - buffer << u8(utf8 >> 8) + g.set_set(v) + return } - `v` { - buffer << `\v` - i++ + + // init struct + // fields: str, len + g.ref(v) + g.literalint(g.data_base + str_pos, ast.voidptr_type) + g.store_field(ast.string_type, ast.voidptr_type, 'str') + g.ref(v) + g.literalint(val.len, ast.int_type) + g.store_field(ast.string_type, ast.int_type, 'len') + } + ast.CallExpr { + // `set_with_expr` is never called with a multireturn call expression + is_pt := g.is_param_type(v.typ) + + g.call_expr(init, v.typ, if is_pt { [v] } else { []Var{} }) + if !is_pt { + g.set(v) } - `x` { - i++ - c := strconv.parse_int(str[i..i + 2], 16, 8) or { - g.w_error('invalid \\x escape code (${str[i..i + 2]})') - 0 + } + ast.ArrayInit { + if !init.is_fixed { + g.v_error('wasm backend does not support non fixed arrays yet', init.pos) + } + + elm_typ := init.elem_type + elm_size, _ := g.pool.type_size(elm_typ) + + if !init.has_val { + arr_size, _ := g.pool.type_size(v.typ) + + g.zero_fill(v, arr_size) + return + } + + mut voff := g.offset(v, elm_typ, 0) // index zero + + for e in init.exprs { + g.set_with_expr(e, voff) + voff = g.offset(voff, elm_typ, elm_size) + } + } + else { + // impl of set but taken out + + if !v.is_address { + g.expr(init, v.typ) + if v.is_global { + g.func.global_set(v.g_idx) + } else { + g.func.local_set(v.idx) } - i += 2 - buffer << u8(c) + return } - `0`...`7` { - c := strconv.parse_int(str[i..i + 3], 8, 8) or { - g.w_error('invalid escape code \\${str[i..i + 3]}') - 0 + + if g.is_pure_type(v.typ) { + if v.is_global { + g.func.global_get(v.g_idx) + } else { + g.func.local_get(v.idx) } - i += 3 - buffer << u8(c) + g.expr(init, v.typ) + g.store(v.typ, v.offset) + return } - else { - g.w_error('invalid escape code \\${str[i]}') + + if var := g.get_var_from_expr(init) { + g.mov(v, var) + return + } + + from := Var{ + typ: v.typ + idx: g.func.new_local_named(.i32_t, '__tmp') + is_address: v.is_address // true + } + + g.expr(init, v.typ) + g.func.local_set(from.idx) + g.mov(v, from) + } + } +} + +pub fn calc_padding(value int, alignment int) int { + if alignment == 0 { + return value + } + return (alignment - value % alignment) % alignment +} + +pub fn calc_align(value int, alignment int) int { + if alignment == 0 { + return value + } + return (value + alignment - 1) / alignment * alignment +} + +pub fn (mut g Gen) make_vinit() { + g.func = g.mod.new_function('_vinit', [], []) + func_start := g.func.patch_pos() + { + for mod_name in g.table.modules { + if mod_name == 'v.reflection' { + g.w_error('the wasm backend does not implement `v.reflection` yet') + } + init_fn_name := if mod_name != 'builtin' { '${mod_name}.init' } else { 'init' } + if _ := g.table.find_fn(init_fn_name) { + g.func.call(init_fn_name) + } + cleanup_fn_name := if mod_name != 'builtin' { '${mod_name}.cleanup' } else { 'cleanup' } + if _ := g.table.find_fn(cleanup_fn_name) { + g.func.call(cleanup_fn_name) } } + for _, gv in g.global_vars { + if init := gv.init { + g.set_with_expr(init, gv.v) + } + } + g.bare_function_frame(func_start) + } + g.mod.commit(g.func, false) + g.bare_function_end() +} + +pub fn (mut g Gen) housekeeping() { + g.make_vinit() + + heap_base := calc_align(g.data_base + g.pool.buf.len, 16) // 16? + page_boundary := calc_align(g.data_base + g.pool.buf.len, 64 * 1024) + preallocated_pages := page_boundary / (64 * 1024) + + if g.pref.is_verbose { + eprintln('housekeeping(): acceptable addresses are > 1024') + eprintln('housekeeping(): stack top: ${g.stack_top}, data_base: ${g.data_base} (size: ${g.pool.buf.len}), heap_base: ${heap_base}') + eprintln('housekeeping(): preallocated pages: ${preallocated_pages}') } - return buffer.bytestr() -} + if sp := g.sp_global { + g.mod.assign_global_init(sp, wasm.constexpr_value(g.stack_top)) + } + if g.sp_global != none || g.pool.buf.len > 0 { + g.mod.assign_memory('memory', true, u32(preallocated_pages), none) + if g.pool.buf.len > 0 { + mut buf := g.pool.buf.clone() -struct ConstantData { - offset int - data []u8 -} - -fn (mut g Gen) constant_data_intern_offset(data []u8) ?(int, int) { - for d in g.constant_data { - if d.data == data { - return d.offset, d.data.len + for reloc in g.pool.relocs { + binary.little_endian_put_u32_at(mut buf, u32(g.data_base + reloc.offset), + reloc.pos) + } + g.mod.new_data_segment(none, g.data_base, buf) } } - return none -} + if hp := g.heap_base { + g.mod.assign_global_init(hp, wasm.constexpr_value(heap_base)) + } -// (offset, len) -fn (mut g Gen) allocate_string(node ast.StringLiteral) (int, int) { - data := g.eval_escape_codes(node).bytes() - - // `-prod` will only intern strings. - if g.pref.is_prod { - if offset, len := g.constant_data_intern_offset(data) { - return offset, len + if g.pref.os == .wasi { + mut fn_start := g.mod.new_function('_start', [], []) + { + fn_start.call('_vinit') + fn_start.call('main.main') } + g.mod.commit(fn_start, true) + } else { + g.mod.assign_start('_vinit') } - - offset := g.constant_data_offset - g.constant_data << ConstantData{ - offset: offset - data: data - } - - padding := (8 - offset % 8) % 8 - g.constant_data_offset += data.len + padding - - return offset, data.len } diff --git a/vlib/v/gen/wasm/ops.v b/vlib/v/gen/wasm/ops.v index c602effd32..895cc593ba 100644 --- a/vlib/v/gen/wasm/ops.v +++ b/vlib/v/gen/wasm/ops.v @@ -1,69 +1,73 @@ +// Copyright (c) 2023 l-m.dev. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. module wasm import v.ast import v.token -import v.gen.wasm.binaryen +import wasm -const ( - type_none = binaryen.typenone() - type_auto = binaryen.typeauto() - type_i32 = binaryen.typeint32() - type_i64 = binaryen.typeint64() - type_f32 = binaryen.typefloat32() - type_f64 = binaryen.typefloat64() -) +pub fn (mut g Gen) as_numtype(a wasm.ValType) wasm.NumType { + if a in [.funcref_t, .externref_t, .v128_t] { + g.w_error("as_numtype: called with '${a}'") + } + + return unsafe { wasm.NumType(a) } +} + +// unwraps int_literal to i64_t +pub fn (mut g Gen) get_wasm_type_int_literal(typ_ ast.Type) wasm.ValType { + if typ_ == ast.int_literal_type_idx { + return wasm.ValType.i64_t + } + return g.get_wasm_type(typ_) +} // "Register size" types such as int, i64 and bool boil down to their WASM counterparts. // Structures and unions are pointers, i32. -fn (mut g Gen) get_wasm_type(typ_ ast.Type) binaryen.Type { +pub fn (mut g Gen) get_wasm_type(typ_ ast.Type) wasm.ValType { typ := ast.mktyp(typ_) if typ == ast.void_type_idx { - return wasm.type_none + g.w_error("get_wasm_type: called with 'void'") } - if typ.is_any_kind_of_pointer() { - g.needs_stack = true - return wasm.type_i32 + if typ.is_ptr() || typ.is_pointer() { + return wasm.ValType.i32_t } if typ in ast.number_type_idxs { return match typ { ast.isize_type_idx, ast.usize_type_idx, ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.rune_type_idx, ast.i16_type_idx, ast.u16_type_idx, ast.int_type_idx, ast.u32_type_idx { - wasm.type_i32 + wasm.ValType.i32_t } - ast.i64_type_idx, ast.u64_type_idx, ast.int_literal_type_idx { - wasm.type_i64 + ast.i64_type_idx, ast.u64_type_idx { + wasm.ValType.i64_t } ast.f32_type_idx { - wasm.type_f32 + wasm.ValType.f32_t } - ast.f64_type_idx, ast.float_literal_type_idx { - wasm.type_f64 + ast.f64_type_idx { + wasm.ValType.f64_t } else { - wasm.type_i32 + wasm.ValType.i32_t } } } if typ == ast.bool_type_idx { - return wasm.type_i32 + return wasm.ValType.i32_t } ts := g.table.sym(typ) match ts.info { ast.Struct { - g.get_type_size_align(typ) - return wasm.type_i32 // pointer - } - ast.MultiReturn { - // TODO: cache?? - mut paraml := ts.info.types.map(g.get_wasm_type(it)) - return binaryen.typecreate(paraml.data, paraml.len) + g.pool.type_size(typ) + return wasm.ValType.i32_t // pointer } ast.Alias { return g.get_wasm_type(ts.info.parent_type) } ast.ArrayFixed { - return wasm.type_i32 + return wasm.ValType.i32_t // pointer } ast.Enum { return g.get_wasm_type(ts.info.typ) @@ -74,251 +78,68 @@ fn (mut g Gen) get_wasm_type(typ_ ast.Type) binaryen.Type { g.w_error("get_wasm_type: unreachable type '${*g.table.sym(typ)}' ${ts.info}") } -fn infix_kind_return_bool(op token.Kind) bool { - return op in [.eq, .ne, .gt, .lt, .ge, .le] -} - -fn (mut g Gen) infix_from_typ(typ ast.Type, op token.Kind) binaryen.Op { - wasm_typ := g.get_wasm_type(typ) - - match wasm_typ { - wasm.type_i32 { - match op { - .plus { - return binaryen.addint32() - } - .minus { - return binaryen.subint32() - } - .mul { - return binaryen.mulint32() - } - .mod { - if typ.is_signed() { - return binaryen.remsint32() - } else { - return binaryen.remuint32() - } - } - .div { - if typ.is_signed() { - return binaryen.divsint32() - } else { - return binaryen.divuint32() - } - } - .eq { - return binaryen.eqint32() - } - .ne { - return binaryen.neint32() - } - .gt { - if typ.is_signed() { - return binaryen.gtsint32() - } else { - return binaryen.gtuint32() - } - } - .lt { - if typ.is_signed() { - return binaryen.ltsint32() - } else { - return binaryen.ltuint32() - } - } - .ge { - if typ.is_signed() { - return binaryen.gesint32() - } else { - return binaryen.geuint32() - } - } - .le { - if typ.is_signed() { - return binaryen.lesint32() - } else { - return binaryen.leuint32() - } - } - /*.logical_or { - return binaryen.orint32() // TODO: logical or - }*/ - .xor { - return binaryen.xorint32() - } - .pipe { - return binaryen.orint32() - } - .amp { - return binaryen.andint32() - } - .left_shift { - return binaryen.shlint32() - } - .right_shift { - return binaryen.shrsint32() - } - .unsigned_right_shift { - return binaryen.shruint32() - } - else {} - } - } - wasm.type_i64 { - match op { - .plus { - return binaryen.addint64() - } - .minus { - return binaryen.subint64() - } - .mul { - return binaryen.mulint64() - } - .mod { - if typ.is_signed() { - return binaryen.remsint64() - } else { - return binaryen.remuint64() - } - } - .div { - if typ.is_signed() { - return binaryen.divsint64() - } else { - return binaryen.divuint64() - } - } - .eq { - return binaryen.eqint64() - } - .ne { - return binaryen.neint64() - } - .gt { - if typ.is_signed() { - return binaryen.gtsint64() - } else { - return binaryen.gtuint64() - } - } - .lt { - if typ.is_signed() { - return binaryen.ltsint64() - } else { - return binaryen.ltuint64() - } - } - .ge { - if typ.is_signed() { - return binaryen.gesint64() - } else { - return binaryen.geuint64() - } - } - .le { - if typ.is_signed() { - return binaryen.lesint64() - } else { - return binaryen.leuint64() - } - } - /*.logical_or { - return binaryen.orint64() // TODO: logical or - }*/ - .xor { - return binaryen.xorint64() - } - .pipe { - return binaryen.orint64() - } - .amp { - return binaryen.andint64() - } - .left_shift { - return binaryen.shlint64() - } - .right_shift { - return binaryen.shrsint64() - } - .unsigned_right_shift { - return binaryen.shruint64() - } - else {} - } - } - wasm.type_f32 { - match op { - .plus { - return binaryen.addfloat32() - } - .minus { - return binaryen.subfloat32() - } - .mul { - return binaryen.mulfloat32() - } - .div { - return binaryen.divfloat32() - } - .eq { - return binaryen.eqfloat32() - } - .ne { - return binaryen.nefloat32() - } - .gt { - return binaryen.gtfloat32() - } - .lt { - return binaryen.ltfloat32() - } - .ge { - return binaryen.gefloat32() - } - .le { - return binaryen.lefloat32() - } - else {} - } - } - wasm.type_f64 { - match op { - .plus { - return binaryen.addfloat64() - } - .minus { - return binaryen.subfloat64() - } - .mul { - return binaryen.mulfloat64() - } - .div { - return binaryen.divfloat64() - } - .eq { - return binaryen.eqfloat64() - } - .ne { - return binaryen.nefloat64() - } - .gt { - return binaryen.gtfloat64() - } - .lt { - return binaryen.ltfloat64() - } - .ge { - return binaryen.gefloat64() - } - .le { - return binaryen.lefloat64() - } - else {} - } - } - else {} +pub fn (mut g Gen) infix_from_typ(typ ast.Type, op token.Kind) { + if g.is_param_type(typ) { + eprintln(*g.table.sym(typ)) + panic('unimplemented') + } + + wasm_typ := g.as_numtype(g.get_wasm_type(typ)) + + match op { + .plus { + g.func.add(wasm_typ) + } + .minus { + g.func.sub(wasm_typ) + } + .mul { + g.func.mul(wasm_typ) + } + .mod { + g.func.rem(wasm_typ, typ.is_signed()) + } + .div { + g.func.div(wasm_typ, typ.is_signed()) + } + .eq { + g.func.eq(wasm_typ) + } + .ne { + g.func.ne(wasm_typ) + } + .gt { + g.func.gt(wasm_typ, typ.is_signed()) + } + .lt { + g.func.lt(wasm_typ, typ.is_signed()) + } + .ge { + g.func.ge(wasm_typ, typ.is_signed()) + } + .le { + g.func.le(wasm_typ, typ.is_signed()) + } + .xor { + g.func.b_xor(wasm_typ) + } + .pipe { + g.func.b_or(wasm_typ) + } + .amp { + g.func.b_and(wasm_typ) + } + .left_shift { + g.func.b_shl(wasm_typ) + } + .right_shift { + g.func.b_shr(wasm_typ, true) + } + .unsigned_right_shift { + g.func.b_shr(wasm_typ, false) + } + else { + g.w_error('bad infix: op `${op}`') + } } - g.w_error('bad infix: op `${op}`') } diff --git a/vlib/v/gen/wasm/serialisation.v b/vlib/v/gen/wasm/serialisation.v deleted file mode 100644 index a809664b1d..0000000000 --- a/vlib/v/gen/wasm/serialisation.v +++ /dev/null @@ -1,168 +0,0 @@ -module wasm - -import v.ast -import v.gen.wasm.binaryen -import encoding.binary as bin -import math.bits - -fn (mut g Gen) bake_constants_plus_initialisers() []GlobalData { - mut initialisers := []GlobalData{} - - for _, global in g.globals { - match global.init { - /* - ast.ArrayInit { - // TODO: call a seraliser recursively over all elements - - if !global.init.is_fixed { - g.w_error('wasm backend does not support non fixed arrays yet') - } - for global.init - }*/ - ast.BoolLiteral { - g.constant_data << ConstantData{ - offset: global.abs_address - data: [u8(global.init.val)] - } - } - ast.FloatLiteral { - mut buf := []u8{len: 8} - wtyp := g.get_wasm_type(global.ast_typ) - match wtyp { - type_f32 { - bin.little_endian_put_u32(mut buf, bits.f32_bits(global.init.val.f32())) - } - type_f64 { - bin.little_endian_put_u64(mut buf, bits.f64_bits(global.init.val.f64())) - unsafe { - buf.len = 4 - } - } - else {} - } - - g.constant_data << ConstantData{ - offset: global.abs_address - data: buf - } - } - ast.StringLiteral { - offset, len := g.allocate_string(global.init) - - if g.table.sym(global.ast_typ).info !is ast.Struct { - mut buf := []u8{len: 4} - bin.little_endian_put_u32(mut buf, u32(offset)) - g.constant_data << ConstantData{ - offset: global.abs_address - data: buf - } - } else { - mut buf := []u8{len: 8} - bin.little_endian_put_u32(mut buf, u32(offset)) - bin.little_endian_put_u32_at(mut buf, u32(len), 4) - - g.constant_data << ConstantData{ - offset: global.abs_address - data: buf - } - } - } - ast.IntegerLiteral { - mut buf := []u8{len: 8} - wtyp := g.get_wasm_type(global.ast_typ) - match wtyp { - type_i32 { - bin.little_endian_put_u32(mut buf, u32(global.init.val.int())) - } - type_i64 { - bin.little_endian_put_u64(mut buf, u64(global.init.val.i64())) - unsafe { - buf.len = 4 - } - } - else {} - } - - g.constant_data << ConstantData{ - offset: global.abs_address - data: buf - } - } - else { - initialisers << global - } - } - } - - return initialisers -} - -fn round_up_to_multiple(val int, multiple int) int { - return val + (multiple - val % multiple) % multiple -} - -fn (mut g Gen) make_vinit() binaryen.Function { - runtime_inits := g.bake_constants_plus_initialisers() - - g.bare_function_start() - - mut body := runtime_inits.map(g.set_var_v(it.to_var(''), g.expr(it.init, it.ast_typ))) - - for mod_name in g.table.modules { - if mod_name == 'v.reflection' { - g.w_error('the wasm backend does not implement `v.reflection` yet') - } - - init_fn_name := if mod_name != 'builtin' { '${mod_name}.init' } else { 'init' } - if _ := g.table.find_fn(init_fn_name) { - body << binaryen.call(g.mod, init_fn_name.str, unsafe { nil }, 0, type_none) - } - cleanup_fn_name := if mod_name != 'builtin' { '${mod_name}.cleanup' } else { 'cleanup' } - if _ := g.table.find_fn(cleanup_fn_name) { - body << binaryen.call(g.mod, cleanup_fn_name.str, unsafe { nil }, 0, type_none) - } - } - - return g.bare_function('_vinit', g.mkblock(body)) -} - -fn (mut g Gen) housekeeping() { - // `_vinit` should be used to initialise the WASM module, - // then `main.main` can be called safely. - vinit := g.make_vinit() - stack_base := round_up_to_multiple(g.constant_data_offset, 1024) - heap_base := if g.needs_stack { - stack_base + 1024 * 16 // 16KiB of stack - } else { - stack_base - } - pages_needed := heap_base / (1024 * 64) + 1 - - if g.needs_stack || g.constant_data.len != 0 { - data := g.constant_data.map(it.data.data) - data_len := g.constant_data.map(it.data.len) - data_offsets := g.constant_data.map(binaryen.constant(g.mod, binaryen.literalint32(it.offset))) - passive := []bool{len: g.constant_data.len, init: false} - - binaryen.setmemory(g.mod, pages_needed, pages_needed + 4, c'memory', data.data, - passive.data, data_offsets.data, data_len.data, data.len, false, false, c'memory') - binaryen.addglobal(g.mod, c'__heap_base', type_i32, false, g.literalint(heap_base, - ast.int_type)) - } - if g.needs_stack { - // `g.constant_data_offset` rounded up to a multiple of 1024 - binaryen.addglobal(g.mod, c'__vsp', type_i32, true, g.literalint(stack_base, ast.int_type)) - } - if g.pref.os == .wasi { - main_expr := g.mkblock([binaryen.call(g.mod, c'_vinit', unsafe { nil }, 0, type_none), - binaryen.call(g.mod, c'main.main', unsafe { nil }, 0, type_none)]) - binaryen.addfunction(g.mod, c'_start', type_none, type_none, unsafe { nil }, 0, - main_expr) - binaryen.addfunctionexport(g.mod, c'_start', c'_start') - } else { - // In `browser` mode, and function can be exported and called regardless. - // To avoid uninitialised data, `_vinit` is set to be ran immediately on - // WASM module creation. - binaryen.setstart(g.mod, vinit) - } -} diff --git a/vlib/v/gen/wasm/serialise/alignment_test.v b/vlib/v/gen/wasm/serialise/alignment_test.v new file mode 100644 index 0000000000..79175d054b --- /dev/null +++ b/vlib/v/gen/wasm/serialise/alignment_test.v @@ -0,0 +1,12 @@ +import v.ast +import v.gen.wasm.serialise + +fn test_alignment() { + table := ast.new_table() + + mut pool := serialise.new_pool(table) + pool.append(ast.BoolLiteral{ val: true }, 0) // +0, +1 + pool.append(ast.FloatLiteral{ val: '0' }, ast.f32_type) // +3, +4 + pool.append(ast.BoolLiteral{ val: true }, 0) // +0, +1 + assert pool.buf.len == 9 +} diff --git a/vlib/v/gen/wasm/serialise/serialise.v b/vlib/v/gen/wasm/serialise/serialise.v new file mode 100644 index 0000000000..c475c9682e --- /dev/null +++ b/vlib/v/gen/wasm/serialise/serialise.v @@ -0,0 +1,449 @@ +// Copyright (c) 2023 l-m.dev. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module serialise + +import v.ast +// import v.eval +import math.bits +import strconv + +[noinit] +pub struct Pool { +mut: + table &ast.Table + // eval eval.Eval + structs map[ast.Type]StructInfo + strings []StringInfo // string intern +pub: + null_terminated bool + intern_strings bool + store_relocs bool +pub mut: + buf []u8 + relocs []Reloc + highest_alignment int +} + +struct StringInfo { + pos int + len int +} + +pub struct StructInfo { +pub mut: + offsets []int +} + +pub struct Reloc { +pub: + pos int + offset int +} + +pub fn (mut p Pool) type_struct_info(typ ast.Type) ?StructInfo { + ts := p.table.sym(typ) + + if ts.info !is ast.Struct { + return none + } + + if typ.idx() in p.structs { + return p.structs[typ.idx()] + } + + // will cache inside `p.structs` + p.type_size(typ) + return p.structs[typ.idx()] +} + +pub fn (mut p Pool) type_size(typ ast.Type) (int, int) { + ts := p.table.sym(typ) + if ts.size != -1 && typ.idx() in p.structs { + return ts.size, ts.align + } + + if ts.info is ast.Enum { + return p.table.type_size(ts.info.typ) + } + + if ts.info !is ast.Struct { + return p.table.type_size(typ) + } + + ti := ts.info as ast.Struct + + // code borrowed from native, inserted in wasm, and now here! + + mut strc := StructInfo{} + mut size := 0 + mut align := 1 + for f in ti.fields { + f_size, f_align := p.type_size(f.typ) + if f_size == 0 { + strc.offsets << 0 + continue + } + padding := (f_align - size % f_align) % f_align + strc.offsets << size + padding + size += f_size + padding + if f_align > align { + align = f_align + } + } + size = (size + align - 1) / align * align + p.structs[typ.idx()] = strc + + mut ts_ := p.table.sym(typ) + ts_.size = size + ts_.align = align + + return size, align +} + +[params] +pub struct PoolOpts { + null_terminated bool = true + intern_strings bool = true + store_relocs bool = true +} + +pub fn new_pool(table &ast.Table, opts PoolOpts) Pool { + return Pool{ + table: table + null_terminated: opts.null_terminated + intern_strings: opts.intern_strings + store_relocs: opts.store_relocs + } +} + +fn (mut p Pool) zero_fill(size int) { + // TODO: eventually support a way to utilise a BSS section + + for i := 0; i < size; i++ { + p.buf << 0 + } +} + +fn (mut p Pool) alignment(align int) int { + if align > p.highest_alignment { + p.highest_alignment = align + } + padding := (align - p.buf.len % align) % align + p.zero_fill(padding) + pos := p.buf.len + return pos +} + +/* +fn (mut p Pool) append_struct(init ast.StructInit) ?int { + old_len := p.buf.len + + size, align := p.type_size(v.typ) + ts := g.table.sym(v.typ) + ts_info := ts.info as ast.Struct + + pos := p.alignment(align) + + if init.fields.len == 0 && !(ts_info.fields.any(it.has_default_expr)) { + for i := 0 ; i < size ; i++ { + p.buf << 0 + } + return pos + } + + /* for i, f in ts_info.fields { + field_to_be_set := init.fields.map(it.name).filter(f.name) + } */ + + /* for i, f in ts_info.fields { + field_to_be_set := init.fields.map(it.name).contains(f.name) + + if !field_to_be_set { + offset := g.structs[v.typ.idx()].offsets[i] + offset_var := g.offset(v, f.typ, offset) + + fsize, _ := g.get_type_size_align(f.typ) + + if f.has_default_expr { + g.expr(f.default_expr, f.typ) + g.set(offset_var) + } else { + g.zero_fill(offset_var, fsize) + } + } + } + + for f in init.fields { + field := ts.find_field(f.name) or { + g.w_error('could not find field `${f.name}` on init') + } + + offset := g.structs[v.typ.idx()].offsets[field.i] + offset_var := g.offset(v, f.expected_type, offset) + + g.expr(f.expr, f.expected_type) + g.set(offset_var) + } */ + + return pos +}*/ + +pub fn eval_escape_codes_raw(str string) !string { + mut buffer := []u8{} + + mut i := 0 + for i < str.len { + if str[i] != `\\` { + buffer << str[i] + i++ + continue + } + + // skip \ + i++ + match str[i] { + `\\`, `'`, `"` { + buffer << str[i] + i++ + } + `a`, `b`, `f` { + buffer << str[i] - u8(90) + i++ + } + `n` { + buffer << `\n` + i++ + } + `r` { + buffer << `\r` + i++ + } + `t` { + buffer << `\t` + i++ + } + `u` { + i++ + utf8 := strconv.parse_int(str[i..i + 4], 16, 16) or { + return error('invalid \\u escape code (${str[i..i + 4]})') + } + i += 4 + buffer << u8(utf8) + buffer << u8(utf8 >> 8) + } + `v` { + buffer << `\v` + i++ + } + `x` { + i++ + c := strconv.parse_int(str[i..i + 2], 16, 8) or { + return error('invalid \\x escape code (${str[i..i + 2]})') + } + i += 2 + buffer << u8(c) + } + `0`...`7` { + c := strconv.parse_int(str[i..i + 3], 8, 8) or { + return error('invalid escape code \\${str[i..i + 3]}') + } + i += 3 + buffer << u8(c) + } + else { + return error('invalid escape code \\${str[i]}') + } + } + } + + return buffer.bytestr() +} + +pub fn eval_escape_codes(str_lit ast.StringLiteral) !string { + if str_lit.is_raw { + return str_lit.val + } + + return eval_escape_codes_raw(str_lit.val) +} + +pub fn (mut p Pool) append_string(val string) int { + data := val.bytes() + + if p.intern_strings { + for str in p.strings { + if data.len > str.len || (p.null_terminated && data.len != str.len) { + continue + } + + // TODO: aggressive string interning if `p.null_terminated` + if p.buf[str.pos..str.pos + data.len] == data { + return str.pos + } + } + } + + pos := p.buf.len + p.buf << data + if p.null_terminated { + p.buf << 0 + } + + p.strings << StringInfo{ + pos: pos + len: data.len + } + + return pos +} + +pub fn (mut p Pool) append(init ast.Expr, typ ast.Type) (int, bool) { + match init { + ast.BoolLiteral { + pos := p.buf.len + p.buf << u8(init.val) + return pos, true + } + ast.FloatLiteral { + assert typ.is_pure_float() + + mut pos := 0 + if typ == ast.f32_type { + pos = p.alignment(4) + p.u32(bits.f32_bits(init.val.f32())) + } else { + pos = p.alignment(8) + p.u64(bits.f64_bits(init.val.f64())) + } + + return pos, true + } + ast.IntegerLiteral { + assert typ.is_pure_int() + + size, align := p.table.type_size(typ) + pos := p.alignment(align) + + match size { + 1 { + p.u8(u8(init.val.i8())) + } + 2 { + p.u16(u16(init.val.i16())) + } + 4 { + p.u32(u32(init.val.int())) + } + 8 { + p.u64(u64(init.val.i64())) + } + else {} + } + + return pos, true + } + ast.CharLiteral { + // 3 extra bytes for improved program correctness, thank me later + rne := u32(eval_escape_codes_raw(init.val) or { panic('Pool.append: ${err}') }.runes()[0]) + pos := p.alignment(4) + p.u32(rne) + + return pos, true + } + ast.StringLiteral { + val := eval_escape_codes(init) or { panic('Pool.append: ${err}') } + str_pos := p.append_string(val) + + if typ != ast.string_type { + // c'str' + return str_pos, true + } + + _, align := p.type_size(ast.string_type) + tss := p.table.sym(ast.string_type).info as ast.Struct + pos := p.alignment(align) + + for field in tss.fields { + match field.name { + 'str' { + p.ptr(str_pos) + } + 'len' { + p.u32(u32(val.len)) + } + 'is_lit' { + p.u32(1) + } + else { + panic('ast.string: field `${field.name}` is unknown') + } + } + } + + return pos, true + } + else { + size, align := p.type_size(typ) + pos := p.alignment(align) + p.zero_fill(size) + return pos, false + } + } +} + +fn (mut p Pool) u64(v u64) { + p.buf << u8(v) + p.buf << u8(v >> u64(8)) + p.buf << u8(v >> u64(16)) + p.buf << u8(v >> u64(24)) + p.buf << u8(v >> u64(32)) + p.buf << u8(v >> u64(40)) + p.buf << u8(v >> u64(48)) + p.buf << u8(v >> u64(56)) +} + +fn (mut p Pool) u32(v u32) { + p.buf << u8(v) + p.buf << u8(v >> u32(8)) + p.buf << u8(v >> u32(16)) + p.buf << u8(v >> u32(24)) +} + +fn (mut p Pool) u16(v u16) { + p.buf << u8(v) + p.buf << u8(v >> u32(8)) +} + +fn (mut p Pool) u8(v u8) { + p.buf << v +} + +fn (mut p Pool) ptr(offset int) int { + assert p.table.pointer_size in [1, 2, 4, 8] + pos := p.buf.len // p.alignment(p.table.pointer_size) + + if p.store_relocs { + p.relocs << Reloc{ + pos: pos + offset: offset + } + } + + match p.table.pointer_size { + 1 { + p.u8(u8(offset)) + } + 2 { + p.u16(u16(offset)) + } + 4 { + p.u32(u32(offset)) + } + 8 { + p.u64(u64(offset)) + } + else {} + } + return pos +} diff --git a/vlib/v/gen/wasm/tests/arith.vv b/vlib/v/gen/wasm/tests/arith.vv index 9ed4573322..413d69dc45 100644 --- a/vlib/v/gen/wasm/tests/arith.vv +++ b/vlib/v/gen/wasm/tests/arith.vv @@ -84,3 +84,60 @@ pub fn powi(a i64, b i64) i64 { return v } + +pub fn sqrti(a i64) i64 { + mut x := a + mut q, mut r := i64(1), i64(0) + for ; q <= x; { + q <<= 2 + } + for ; q > 1; { + q >>= 2 + t := x - r - q + r >>= 1 + if t >= 0 { + x = t + r += q + } + } + return r +} + +fn main() { + println('--- test printing numbers') + println(-20) + println(0) + println(22) + println(-1000000022) + + println('--- test powi') + println(powi(2, 62)) + println(powi(0, -2)) + println(powi(2, -1)) + + println('--- test sqrti') + println(sqrti(i64(123456789) * i64(123456789))) + println(sqrti(144)) + println(sqrti(0)) + + println('--- test negate') + println(negate(20)) + println(negate(-1)) + + println('--- test inc') + println(inc(20)) + println(inc(-1)) + + println('--- test lcm') + println(lcm(2, 3)) + println(lcm(-2, 3)) + println(lcm(-2, -3)) + println(lcm(0, 0)) + + println('--- test gcd') + + println(gcd(6, 9)) + println(gcd(6, -9)) + println(gcd(-6, -9)) + println(gcd(0, 0)) +} diff --git a/vlib/v/gen/wasm/tests/arith.vv.out b/vlib/v/gen/wasm/tests/arith.vv.out new file mode 100644 index 0000000000..5b347edac3 --- /dev/null +++ b/vlib/v/gen/wasm/tests/arith.vv.out @@ -0,0 +1,29 @@ +--- test printing numbers +-20 +0 +22 +-1000000022 +--- test powi +4611686018427387904 +-1 +0 +--- test sqrti +123456789 +12 +0 +--- test negate +-20 +1 +--- test inc +20 +-1 +--- test lcm +6 +6 +6 +0 +--- test gcd +3 +3 +3 +0 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/arrays.vv b/vlib/v/gen/wasm/tests/arrays.vv index 8fbb60623c..35c9aa016b 100644 --- a/vlib/v/gen/wasm/tests/arrays.vv +++ b/vlib/v/gen/wasm/tests/arrays.vv @@ -3,12 +3,14 @@ struct TEST { b i64 } -fn static_arrays() { +fn static_arrays() (int, int, i64) { a := [8]int{} b := [10, 12, 150]! c := [TEST{}, TEST{ b: 10 }]! + + return a[2], b[1], c[1].b } fn index_expression() { @@ -16,7 +18,11 @@ fn index_expression() { a := b[2] c := 'hello'[4] - d := c'hello'[2] + d := unsafe { c'hello'[2] } + + println(a) + println(c) + println(d) } fn test_this(index int) int { @@ -31,9 +37,31 @@ struct AA { a [10]&int } -fn main() { +fn test_stuff() &int { a := AA{} mut b := &int(0) b = a.a[2] + + return b +} + +fn main() { + println('--- static_arrays()') + a, b, c := static_arrays() + println(a) + println(b) + println(c) + + println('--- index_expression()') + index_expression() + + println('--- test_this()') + println(test_this(2)) + println(test_this(10)) + println(test_this(-1)) + + println('--- test_stuff()') + v := test_stuff() + println(v) } diff --git a/vlib/v/gen/wasm/tests/arrays.vv.out b/vlib/v/gen/wasm/tests/arrays.vv.out new file mode 100644 index 0000000000..a710bbc412 --- /dev/null +++ b/vlib/v/gen/wasm/tests/arrays.vv.out @@ -0,0 +1,14 @@ +--- static_arrays() +0 +12 +10 +--- index_expression() +150 +111 +108 +--- test_this() +108 +10 +10 +--- test_stuff() +0 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/builtin.vv b/vlib/v/gen/wasm/tests/builtin.vv index 3358959137..d3ae20adb7 100644 --- a/vlib/v/gen/wasm/tests/builtin.vv +++ b/vlib/v/gen/wasm/tests/builtin.vv @@ -1,7 +1,6 @@ fn test() { print('hello!') println('hello!') - panic('nooo!') } fn str_methods() { @@ -16,3 +15,19 @@ fn str_implicit() { a := 100 println(a + 10) } + +fn assertions() { + assert true, 'hello' + assert true + + // assert false, 'no can do' +} + +fn main() { + test() + str_methods() + str_implicit() + assertions() + + // panic('nooo!') +} diff --git a/vlib/v/gen/wasm/tests/builtin.vv.out b/vlib/v/gen/wasm/tests/builtin.vv.out new file mode 100644 index 0000000000..3abad377ed --- /dev/null +++ b/vlib/v/gen/wasm/tests/builtin.vv.out @@ -0,0 +1,6 @@ +hello!hello! +128-192322 +false +false +true +110 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/control_flow.vv b/vlib/v/gen/wasm/tests/control_flow.vv index 219f3fb17c..19d32a89d3 100644 --- a/vlib/v/gen/wasm/tests/control_flow.vv +++ b/vlib/v/gen/wasm/tests/control_flow.vv @@ -59,15 +59,17 @@ fn addcfor() int { return val } -fn labelcfor() { +fn labelcfor() (int, int) { + mut idx := 0 mut val := 0 hello: for { for { + val++ if val == 10 { continue hello } - val++ + idx++ if val == 100 { break hello @@ -75,6 +77,8 @@ fn labelcfor() { } break } + + return val, idx } fn infcfor() int { @@ -89,3 +93,32 @@ fn infcfor() int { return 0 } + +fn main() { + println('--- func()') + println(func(10, true)) + println(func(0, false)) + println(func(0, true)) + + println('--- test()') + println(test(true)) + println(test(false)) + println(test(true && false)) + + println('--- boolfor()') + println(boolfor()) + + println('--- inffor()') + println(inffor()) + + println('--- addcfor()') + println(addcfor()) + + println('--- labelcfor()') + a, b := labelcfor() + println(a) + println(b) + + println('--- infcfor()') + println(infcfor()) +} diff --git a/vlib/v/gen/wasm/tests/control_flow.vv.out b/vlib/v/gen/wasm/tests/control_flow.vv.out new file mode 100644 index 0000000000..f990171f80 --- /dev/null +++ b/vlib/v/gen/wasm/tests/control_flow.vv.out @@ -0,0 +1,19 @@ +--- func() +10 +0 +0 +--- test() +2 +5 +5 +--- boolfor() +1 +--- inffor() +1 +--- addcfor() +45 +--- labelcfor() +100 +99 +--- infcfor() +10 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/misc.vv b/vlib/v/gen/wasm/tests/misc.vv index 171fabdb14..aecc263ba0 100644 --- a/vlib/v/gen/wasm/tests/misc.vv +++ b/vlib/v/gen/wasm/tests/misc.vv @@ -6,9 +6,10 @@ enum Hello as u64 { e } -fn enums() { +fn enums() Hello { mut a := Hello.a a = .c + return a } struct AA { @@ -19,6 +20,7 @@ struct AA { fn of() { a := __offsetof(AA, b) b := sizeof(AA) + _, _ := a, b } fn constant() int { @@ -55,3 +57,35 @@ fn ptr_arith() { } println((*b).str()) } + +fn defer_if(cond bool) { + if cond { + defer { + println('defer_if: defer!') + } + } + println('defer_if: start') +} + +fn run_defer() { + defer { + println('defer!') + } + println('before defer') + defer_if(true) + defer_if(false) +} + +fn main() { + println('ptr_arith') + ptr_arith() + run_defer() + println('constants') + println(runtime_init) + println(hello) + // println(float) + println(integer) + println('enums') + println(int(enums())) + println(sizeof(Hello)) +} diff --git a/vlib/v/gen/wasm/tests/misc.vv.out b/vlib/v/gen/wasm/tests/misc.vv.out new file mode 100644 index 0000000000..bb89ccbcd8 --- /dev/null +++ b/vlib/v/gen/wasm/tests/misc.vv.out @@ -0,0 +1,17 @@ +ptr_arith +12 +14 +102 +before defer +defer_if: start +defer_if: defer! +defer_if: start +defer! +constants +100 +hello + +888 +enums +30 +8 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/multi_expr.vv b/vlib/v/gen/wasm/tests/multi_expr.vv index 784dafd9ca..73d314eda0 100644 --- a/vlib/v/gen/wasm/tests/multi_expr.vv +++ b/vlib/v/gen/wasm/tests/multi_expr.vv @@ -3,7 +3,7 @@ fn multi(a i16) i64 { return one + two } -pub fn multireturn(a int) (int, f64, i64) { +pub fn multireturn(a int) (int, i64, i64) { return 2, a + 2, 10 - a } @@ -21,10 +21,94 @@ pub fn side_effect() int { return 22 } -pub fn test_side_effect() int { +pub fn run_side_effect() int { mut a := 15 _, a = side_effect(), 10 return a } + +fn run_normal_stuff() { + println(multi(2)) + { + a, b, c := multireturn(20) + println(a) + println(b) + println(c) + } + println(accept()) + println(run_side_effect()) +} + +fn if_cond(cond bool) (int, int) { + return if cond { 10, 15 } else { 30, 35 } +} + +struct AA { + a int + b int +} + +fn take_struct(test AA) int { + return test.a +} + +fn give_two_struct(cond bool) (AA, AA) { + return if cond { + AA{ + a: 15 + }, AA{ + a: 15 + } + } else { + AA{ + a: 20 + }, AA{ + a: 592 + } + } +} + +fn give_struct() int { + return take_struct(AA{ a: 15 }) +} + +fn if_struct_test(cond bool) AA { + a := if cond { + AA{} + } else { + AA{ + a: 125 + } + } + return a +} + +fn run_stmt_exprs() { + mut a := 0 + mut b := 0 + a, b = if_cond(true) + println(true) + println(a) + println(b) + a, b = if_cond(false) + println(false) + println(a) + println(b) + println(give_struct()) + mut struc := if_struct_test(false) + println(struc.a) + struc = if_struct_test(true) + println(struc.a) + c, d := give_two_struct(false) + println(c.a) + println(d.a) +} + +fn main() { + println('--- normal multi exprs') + run_normal_stuff() + println('--- struct based multi exprs/stmt exprs') + run_stmt_exprs() +} diff --git a/vlib/v/gen/wasm/tests/multi_expr.vv.out b/vlib/v/gen/wasm/tests/multi_expr.vv.out new file mode 100644 index 0000000000..f29d837f42 --- /dev/null +++ b/vlib/v/gen/wasm/tests/multi_expr.vv.out @@ -0,0 +1,19 @@ +--- normal multi exprs +12 +2 +22 +-10 +45 +10 +--- struct based multi exprs/stmt exprs +true +10 +15 +false +30 +35 +15 +125 +0 +20 +592 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/structs.vv b/vlib/v/gen/wasm/tests/structs.vv index 48b1cc007e..ce6dea66ac 100644 --- a/vlib/v/gen/wasm/tests/structs.vv +++ b/vlib/v/gen/wasm/tests/structs.vv @@ -142,7 +142,7 @@ struct Hello { } pub fn recurse() { - a := Hello{} + _ := Hello{} } struct DD { @@ -177,3 +177,25 @@ fn postfix_test() { fn postfix_test_mut(mut a TEST) { a.b++ } + +fn main() { + zeroed() + field() + println(selector(0)) + println(reassign(10)) + println(give(42)) + println(return_make(123)) + accept() + println(accept_multi(5)) + x, y := test(2, 3) + println(x) + println(y) + recurse() + z, w := valer() + println(z) + println(w) + postfix_test() + mut a := TEST{} + postfix_test_mut(mut a) + println(a.b) +} diff --git a/vlib/v/gen/wasm/tests/structs.vv.out b/vlib/v/gen/wasm/tests/structs.vv.out new file mode 100644 index 0000000000..1562d8c507 --- /dev/null +++ b/vlib/v/gen/wasm/tests/structs.vv.out @@ -0,0 +1,10 @@ +32 +20 +42 +123 +10 +12 +8 +20 +30 +1 \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/wasm_test.v b/vlib/v/gen/wasm/tests/wasm_test.v index 768a106825..6a0b9969a1 100644 --- a/vlib/v/gen/wasm/tests/wasm_test.v +++ b/vlib/v/gen/wasm/tests/wasm_test.v @@ -6,6 +6,23 @@ const is_verbose = os.getenv('VTEST_SHOW_CMD') != '' // TODO some logic copy pasted from valgrind_test.v and compiler_test.v, move to a module fn test_wasm() { + mut runtimes := ['wasmer', 'wasmtime', 'wavm', 'wasm3'] + mut runtime_found := false + + for runtime in runtimes { + basename := $if windows { runtime + '.exe' } $else { runtime } + + if rf := os.find_abs_path_of_executable(basename) { + runtime_found = true + break + } + } + + if !runtime_found { + eprintln('cannot find suitable wasm runtime, exiting...') + exit(0) + } + mut bench := benchmark.new_benchmark() vexe := os.getenv('VEXE') vroot := os.dir(vexe) @@ -33,7 +50,7 @@ fn test_wasm() { tmperrfile := '${dir}/${test}.tmperr' outfile := '${dir}/${test}.out' // force binaryen to print without colour - cmd := '${os.quoted_path(vexe)} -o - -b wasm ${os.quoted_path(full_test_path)} 2> ${os.quoted_path(tmperrfile)}' + cmd := '${os.quoted_path(vexe)} -b wasm run ${os.quoted_path(full_test_path)} 2> ${os.quoted_path(tmperrfile)}' if is_verbose { println(cmd) } @@ -65,6 +82,9 @@ fn test_wasm() { bench.fail() continue } + } else { + os.write_file(outfile, res_wasm.output.trim_right('\r\n').replace('\r\n', + '\n'))! } bench.ok() eprintln(bench.step_message_ok(relative_test_path)) diff --git a/vlib/v/help/build/build-wasm.txt b/vlib/v/help/build/build-wasm.txt new file mode 100644 index 0000000000..1c3fb0f914 --- /dev/null +++ b/vlib/v/help/build/build-wasm.txt @@ -0,0 +1,25 @@ +This command compiles the given target, along with their dependencies, +into an executable using the WebAssembly code generation backend. + +Usage: + v -b wasm [-options] ['run'] [run options] + + +For more general build help, see also `v help build`. + +# Interfacing WebAssembly code generation, passing options to it: + -wasm-validate + After compiling the WebAssembly module, execute wasm-validate to validate the module. + Useful for debugging the compiler. + + -os , -target-os + Change the target WebAssembly execution environment that V compiles for. + + The `wasi` target is the default execution enviroment. + When targeting WASI, the generated WebAssembly module can be run in a variety of environments that support the WASI specification. + WASI provides a standardized interface to interact with the host operating system, allowing WebAssembly modules to perform tasks like file I/O, networking, and more. + The specific version of the WASI specification targeted by V is 'wasi_snapshot_preview1'. + + The `browser` target is an experimental environment that compiles for a stripped down builtin, for use in browsers. + The produced WebAssembly module will have functions exported that are `pub` and inside the `module main`. + See `examples/wasm/mandelbrot` for an example. diff --git a/vlib/v/help/build/build.txt b/vlib/v/help/build/build.txt index 8c49b99138..d274bebe26 100644 --- a/vlib/v/help/build/build.txt +++ b/vlib/v/help/build/build.txt @@ -45,6 +45,7 @@ NB: the build flags are shared with the run command too: * `js_node` - V outputs JS source code to run with nodejs. * `js_freestanding` - V outputs JS source code with no hard runtime dependency. * `native` - V outputs a native executable directly (see -arch x64|arm64 and -os linux|macos) (EXPERIMENTAL). + * `wasm` - V outputs a WebAssembly module directly (see -os wasi|browser) (EXPERIMENTAL). -d [=], -define [=] Define the provided flag. @@ -209,6 +210,7 @@ NB: the build flags are shared with the run command too: For C-specific build flags, use `v help build-c`. For JS-specific build flags, use `v help build-js`. For Native-specific build flags, use `v help build-native`. +For WebAssembly-specific build flags, use `v help build-wasm`. See also: `v help run` for documentation regarding `v run`. diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 95c0ec9b78..053b89d5b7 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -228,6 +228,7 @@ pub mut: // checker settings: checker_match_exhaustive_cutoff_limit int = 12 thread_stack_size int = 8388608 // Change with `-thread-stack-size 4194304`. Note: on macos it was 524288, which is too small for more complex programs with many nested callexprs. + wasm_validate bool // validate webassembly code, by calling `wasm-validate` } pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) { @@ -303,6 +304,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin arg := args[i] current_args := args[i..].clone() match arg { + '-wasm-validate' { + res.wasm_validate = true + } '-apk' { res.is_apk = true res.build_options << arg diff --git a/vlib/v/transformer/transformer.v b/vlib/v/transformer/transformer.v index b8dfa7c87f..c2369139ab 100644 --- a/vlib/v/transformer/transformer.v +++ b/vlib/v/transformer/transformer.v @@ -666,6 +666,21 @@ pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr { ast.UnsafeExpr { node.expr = t.expr(mut node.expr) } + // segfaults with vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v + /* + ast.Ident { + mut obj := node.obj + if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] { + obj = node.scope.find(node.name) or { return node } + } + + match mut obj { + ast.ConstField { + obj.expr = t.expr(mut obj.expr) + } + else {} + } + }*/ else {} } return node diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 3bb8c7268f..f2275b857a 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -163,7 +163,7 @@ pub fn launch_tool(is_verbose bool, tool_name string, args []string) { for emodule in emodules { check_module_is_installed(emodule, is_verbose) or { panic(err) } } - mut compilation_command := '${os.quoted_path(vexe)} -skip-unused ' + mut compilation_command := '${os.quoted_path(vexe)} ' if tool_name in ['vself', 'vup', 'vdoctor', 'vsymlink'] { // These tools will be called by users in cases where there // is high chance of there being a problem somewhere. Thus diff --git a/vlib/wasm/encoding.v b/vlib/wasm/encoding.v index 481537b957..2203e0a472 100644 --- a/vlib/wasm/encoding.v +++ b/vlib/wasm/encoding.v @@ -110,26 +110,22 @@ fn (mut mod Module) patch(ft Function) { mod.buf << ft.code[ptr..] } -// name -pub fn (mut mod Module) name(name string) { +fn (mut mod Module) name(name string) { mod.u32(u32(name.len)) mod.buf << name.bytes() } -// start_subsection -pub fn (mut mod Module) start_subsection(sec Subsection) int { +fn (mut mod Module) start_subsection(sec Subsection) int { mod.buf << u8(sec) return mod.patch_start() } -// start_section -pub fn (mut mod Module) start_section(sec Section) int { +fn (mut mod Module) start_section(sec Section) int { mod.buf << u8(sec) return mod.patch_start() } -// end_section -pub fn (mut mod Module) end_section(tpatch int) { +fn (mut mod Module) end_section(tpatch int) { mod.patch_len(tpatch) } @@ -160,18 +156,14 @@ pub fn (mut mod Module) compile() []u8 { { mod.u32(u32(mod.fn_imports.len + mod.global_imports.len)) for ft in mod.fn_imports { - mod.u32(u32(ft.mod.len)) - mod.buf << ft.mod.bytes() - mod.u32(u32(ft.name.len)) - mod.buf << ft.name.bytes() + mod.name(ft.mod) + mod.name(ft.name) mod.buf << 0x00 // function mod.u32(u32(ft.tidx)) } for gt in mod.global_imports { - mod.u32(u32(gt.mod.len)) - mod.buf << gt.mod.bytes() - mod.u32(u32(gt.name.len)) - mod.buf << gt.name.bytes() + mod.name(gt.mod) + mod.name(gt.name) mod.buf << 0x03 // global mod.global_type(gt.typ, gt.is_mut) } @@ -244,7 +236,7 @@ pub fn (mut mod Module) compile() []u8 { continue } lsz++ - mod.name(ft.name) + mod.name(ft.export_name or { ft.name }) mod.buf << 0x00 // function mod.u32(u32(ft.idx + mod.fn_imports.len)) } diff --git a/vlib/wasm/functions.v b/vlib/wasm/functions.v index 0896bd6173..557e3990f5 100644 --- a/vlib/wasm/functions.v +++ b/vlib/wasm/functions.v @@ -43,4 +43,11 @@ mut: locals []FunctionLocal pub: name string +pub mut: + export_name ?string +} + +// export_name sets the export name of the function to `name` +pub fn (mut func Function) export_name(name string) { + func.export_name = name } diff --git a/vlib/wasm/instructions.v b/vlib/wasm/instructions.v index 4244bce024..c97a2e0114 100644 --- a/vlib/wasm/instructions.v +++ b/vlib/wasm/instructions.v @@ -861,6 +861,17 @@ pub fn (mut func Function) cast_trapping(a NumType, is_signed bool, b NumType) { func.cast(a, is_signed, b) } +// reinterpret returns a value which has the same bit-pattern as its operand value, in its result type. +// WebAssembly instruction: `f32.reinterpret_i32`, `i32.reinterpret_f32`, `f64.reinterpret_i64`, `i64.reinterpret_f64`. +pub fn (mut func Function) reinterpret(a NumType) { + match a { + .f32_t { func.code << 0xBC } // i32.reinterpret_f32 + .i32_t { func.code << 0xBE } // f32.reinterpret_i32 + .f64_t { func.code << 0xBD } // i64.reinterpret_f64 + .i64_t { func.code << 0xBF } // f64.reinterpret_i64 + } +} + // unreachable denotes a point in code that should not be reachable, it is an unconditional trap. // WebAssembly instruction: `unreachable`. pub fn (mut func Function) unreachable() { @@ -919,7 +930,7 @@ pub fn (mut func Function) c_return() { func.code << 0x0F // return } -// c_end ends the block or loop with the label passed in at `label`. +// c_end ends the block, loop or if expression with the label passed in at `label`. pub fn (mut func Function) c_end(label LabelIndex) { assert func.label == label, 'c_end: called with an invalid label ${label}' func.label-- @@ -945,11 +956,6 @@ pub fn (mut func Function) c_br_if(label LabelIndex) { func.u32(u32(v)) } -// c_end_if closes the current if expression. -pub fn (mut func Function) c_end_if() { - func.code << 0x0B // END expression opcode -} - // call calls a locally defined function. // If this function does not exist when calling `compile` on the module, it will panic. // WebAssembly instruction: `call`.