From e1f1a3b49c1e4ca2e18735bfcdae81ed344f28c1 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Thu, 28 Feb 2019 17:36:22 +0100 Subject: [PATCH] Implement v128 instructions (#508) --- .travis.yml | 6 + src/builtins.ts | 2328 +++++++++++++++- src/common.ts | 11 + src/compiler.ts | 12 + src/diagnosticMessages.generated.ts | 4 + src/diagnosticMessages.json | 2 + src/flow.ts | 9 + src/module.ts | 205 +- src/program.ts | 3 + src/resolver.ts | 13 +- src/types.ts | 2 + src/util/index.ts | 5 + std/assembly/builtins.ts | 396 ++- std/assembly/index.d.ts | 472 +++- tests/compiler.js | 43 + tests/compiler/asc-constants.ts | 3 + tests/compiler/asc-constants.untouched.wat | 9 + tests/compiler/simd.json | 5 + tests/compiler/simd.optimized.wat | 21 + tests/compiler/simd.ts | 424 +++ tests/compiler/simd.untouched.wat | 2896 ++++++++++++++++++++ tests/compiler/std/simd.optimized.wat | 11 + tests/compiler/std/simd.ts | 31 + tests/compiler/std/simd.untouched.wat | 12 + tests/features.json | 10 + 25 files changed, 6647 insertions(+), 286 deletions(-) create mode 100644 tests/compiler/simd.json create mode 100644 tests/compiler/simd.optimized.wat create mode 100644 tests/compiler/simd.ts create mode 100644 tests/compiler/simd.untouched.wat create mode 100644 tests/compiler/std/simd.optimized.wat create mode 100644 tests/compiler/std/simd.ts create mode 100644 tests/compiler/std/simd.untouched.wat create mode 100644 tests/features.json diff --git a/.travis.yml b/.travis.yml index 061c816e..21b05598 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,9 @@ jobs: script: - npm run all env: Runs the tests on node.js stable + - node_js: node + script: + - npm run clean && npm run test:compiler + env: + - ASC_FEATURES="simd" + - NVM_NODEJS_ORG_MIRROR="https://nodejs.org/download/v8-canary/" diff --git a/src/builtins.ts b/src/builtins.ts index 350e3967..378b1eb3 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -34,6 +34,10 @@ import { BinaryOp, UnaryOp, HostOp, + AtomicRMWOp, + SIMDExtractOp, + SIMDReplaceOp, + SIMDShiftOp, NativeType, ExpressionRef, ExpressionId, @@ -42,7 +46,8 @@ import { getConstValueI64High, getConstValueI64Low, getConstValueI32, - AtomicRMWOp + getConstValueF32, + getConstValueF64 } from "./module"; import { @@ -68,6 +73,15 @@ import { CommonFlags } from "./common"; +import { + writeI8, + writeI16, + writeI32, + writeF32, + writeF64, + isPowerOf2 +} from "./util"; + /** Symbols of various compiler built-ins. */ export namespace BuiltinSymbols { // std/builtins.ts @@ -83,6 +97,7 @@ export namespace BuiltinSymbols { export const isDefined = "~lib/builtins/isDefined"; export const isConstant = "~lib/builtins/isConstant"; export const isManaged = "~lib/builtins/isManaged"; + export const clz = "~lib/builtins/clz"; export const ctz = "~lib/builtins/ctz"; export const popcnt = "~lib/builtins/popcnt"; @@ -111,6 +126,7 @@ export namespace BuiltinSymbols { export const atomic_cmpxchg = "~lib/builtins/atomic.cmpxchg"; export const atomic_wait = "~lib/builtins/atomic.wait"; export const atomic_notify = "~lib/builtins/atomic.notify"; + export const sizeof = "~lib/builtins/sizeof"; export const alignof = "~lib/builtins/alignof"; export const offsetof = "~lib/builtins/offsetof"; @@ -121,6 +137,7 @@ export namespace BuiltinSymbols { export const unchecked = "~lib/builtins/unchecked"; export const call_indirect = "~lib/builtins/call_indirect"; export const instantiate = "~lib/builtins/instantiate"; + export const i8 = "~lib/builtins/i8"; export const i16 = "~lib/builtins/i16"; export const i32 = "~lib/builtins/i32"; @@ -136,6 +153,7 @@ export namespace BuiltinSymbols { export const f64 = "~lib/builtins/f64"; export const v128 = "~lib/builtins/v128"; export const void_ = "~lib/builtins/void"; + export const i32_clz = "~lib/builtins/i32.clz"; export const i64_clz = "~lib/builtins/i64.clz"; export const i32_ctz = "~lib/builtins/i32.ctz"; @@ -146,6 +164,7 @@ export namespace BuiltinSymbols { export const i64_rotl = "~lib/builtins/i64.rotl"; export const i32_rotr = "~lib/builtins/i32.rotr"; export const i64_rotr = "~lib/builtins/i64.rotr"; + export const f32_abs = "~lib/builtins/f32.abs"; export const f64_abs = "~lib/builtins/f64.abs"; export const f32_max = "~lib/builtins/f32.max"; @@ -168,6 +187,7 @@ export namespace BuiltinSymbols { export const f64_sqrt = "~lib/builtins/f64.sqrt"; export const f32_trunc = "~lib/builtins/f32.trunc"; export const f64_trunc = "~lib/builtins/f64.trunc"; + export const i32_load8_s = "~lib/builtins/i32.load8_s"; export const i32_load8_u = "~lib/builtins/i32.load8_u"; export const i32_load16_s = "~lib/builtins/i32.load16_s"; @@ -191,6 +211,7 @@ export namespace BuiltinSymbols { export const i64_store = "~lib/builtins/i64.store"; export const f32_store = "~lib/builtins/f32.store"; export const f64_store = "~lib/builtins/f64.store"; + export const i32_atomic_load8_u = "~lib/builtins/i32.atomic.load8_u"; export const i32_atomic_load16_u = "~lib/builtins/i32.atomic.load16_u"; export const i32_atomic_load = "~lib/builtins/i32.atomic.load"; @@ -258,6 +279,188 @@ export namespace BuiltinSymbols { export const i64_wait = "~lib/builtins/i64.wait"; export const i32_notify = "~lib/builtins/i32.notify"; export const i64_notify = "~lib/builtins/i64.notify"; + + export const v128_splat = "~lib/builtins/v128.splat"; + export const v128_extract_lane = "~lib/builtins/v128.extract_lane"; + export const v128_replace_lane = "~lib/builtins/v128.replace_lane"; + export const v128_shuffle = "~lib/builtins/v128.shuffle"; + export const v128_load = "~lib/builtins/v128.load"; + export const v128_store = "~lib/builtins/v128.store"; + export const v128_add = "~lib/builtins/v128.add"; + export const v128_sub = "~lib/builtins/v128.sub"; + export const v128_mul = "~lib/builtins/v128.mul"; + export const v128_div = "~lib/builtins/v128.div"; + export const v128_neg = "~lib/builtins/v128.neg"; + export const v128_add_saturate = "~lib/builtins/v128.add_saturate"; + export const v128_sub_saturate = "~lib/builtins/v128.sub_saturate"; + export const v128_shl = "~lib/builtins/v128.shl"; + export const v128_shr = "~lib/builtins/v128.shr"; + export const v128_and = "~lib/builtins/v128.and"; + export const v128_or = "~lib/builtins/v128.or"; + export const v128_xor = "~lib/builtins/v128.xor"; + export const v128_not = "~lib/builtins/v128.not"; + export const v128_bitselect = "~lib/builtins/v128.bitselect"; + export const v128_any_true = "~lib/builtins/v128.any_true"; + export const v128_all_true = "~lib/builtins/v128.all_true"; + export const v128_min = "~lib/builtins/v128.min"; + export const v128_max = "~lib/builtins/v128.max"; + export const v128_abs = "~lib/builtins/v128.abs"; + export const v128_sqrt = "~lib/builtins/v128.sqrt"; + export const v128_eq = "~lib/builtins/v128.eq"; + export const v128_ne = "~lib/builtins/v128.ne"; + export const v128_lt = "~lib/builtins/v128.lt"; + export const v128_le = "~lib/builtins/v128.le"; + export const v128_gt = "~lib/builtins/v128.gt"; + export const v128_ge = "~lib/builtins/v128.ge"; + export const v128_convert = "~lib/builtins/v128.convert"; + export const v128_trunc = "~lib/builtins/v128.trunc"; + + export const i8x16 = "~lib/builtins/i8x16"; + export const i16x8 = "~lib/builtins/i16x8"; + export const i32x4 = "~lib/builtins/i32x4"; + export const i64x2 = "~lib/builtins/i64x2"; + export const f32x4 = "~lib/builtins/f32x4"; + export const f64x2 = "~lib/builtins/f64x2"; + + export const i8x16_splat = "~lib/builtins/i8x16.splat"; + export const i8x16_extract_lane_s = "~lib/builtins/i8x16.extract_lane_s"; + export const i8x16_extract_lane_u = "~lib/builtins/i8x16.extract_lane_u"; + export const i8x16_replace_lane = "~lib/builtins/i8x16.replace_lane"; + export const i8x16_add = "~lib/builtins/i8x16.add"; + export const i8x16_sub = "~lib/builtins/i8x16.sub"; + export const i8x16_mul = "~lib/builtins/i8x16.mul"; + export const i8x16_neg = "~lib/builtins/i8x16.neg"; + export const i8x16_add_saturate_s = "~lib/builtins/i8x16.add_saturate_s"; + export const i8x16_add_saturate_u = "~lib/builtins/i8x16.add_saturate_u"; + export const i8x16_sub_saturate_s = "~lib/builtins/i8x16.sub_saturate_s"; + export const i8x16_sub_saturate_u = "~lib/builtins/i8x16.sub_saturate_u"; + export const i8x16_shl = "~lib/builtins/i8x16.shl"; + export const i8x16_shr_s = "~lib/builtins/i8x16.shr_s"; + export const i8x16_shr_u = "~lib/builtins/i8x16.shr_u"; + export const i8x16_any_true = "~lib/builtins/i8x16.any_true"; + export const i8x16_all_true = "~lib/builtins/i8x16.all_true"; + export const i8x16_eq = "~lib/builtins/i8x16.eq"; + export const i8x16_ne = "~lib/builtins/i8x16.ne"; + export const i8x16_lt_s = "~lib/builtins/i8x16.lt_s"; + export const i8x16_lt_u = "~lib/builtins/i8x16.lt_u"; + export const i8x16_le_s = "~lib/builtins/i8x16.le_s"; + export const i8x16_le_u = "~lib/builtins/i8x16.le_u"; + export const i8x16_gt_s = "~lib/builtins/i8x16.gt_s"; + export const i8x16_gt_u = "~lib/builtins/i8x16.gt_u"; + export const i8x16_ge_s = "~lib/builtins/i8x16.ge_s"; + export const i8x16_ge_u = "~lib/builtins/i8x16.ge_u"; + + export const i16x8_splat = "~lib/builtins/i16x8.splat"; + export const i16x8_extract_lane_s = "~lib/builtins/i16x8.extract_lane_s"; + export const i16x8_extract_lane_u = "~lib/builtins/i16x8.extract_lane_u"; + export const i16x8_replace_lane = "~lib/builtins/i16x8.replace_lane"; + export const i16x8_add = "~lib/builtins/i16x8.add"; + export const i16x8_sub = "~lib/builtins/i16x8.sub"; + export const i16x8_mul = "~lib/builtins/i16x8.mul"; + export const i16x8_neg = "~lib/builtins/i16x8.neg"; + export const i16x8_add_saturate_s = "~lib/builtins/i16x8.add_saturate_s"; + export const i16x8_add_saturate_u = "~lib/builtins/i16x8.add_saturate_u"; + export const i16x8_sub_saturate_s = "~lib/builtins/i16x8.sub_saturate_s"; + export const i16x8_sub_saturate_u = "~lib/builtins/i16x8.sub_saturate_u"; + export const i16x8_shl = "~lib/builtins/i16x8.shl"; + export const i16x8_shr_s = "~lib/builtins/i16x8.shr_s"; + export const i16x8_shr_u = "~lib/builtins/i16x8.shr_u"; + export const i16x8_any_true = "~lib/builtins/i16x8.any_true"; + export const i16x8_all_true = "~lib/builtins/i16x8.all_true"; + export const i16x8_eq = "~lib/builtins/i16x8.eq"; + export const i16x8_ne = "~lib/builtins/i16x8.ne"; + export const i16x8_lt_s = "~lib/builtins/i16x8.lt_s"; + export const i16x8_lt_u = "~lib/builtins/i16x8.lt_u"; + export const i16x8_le_s = "~lib/builtins/i16x8.le_s"; + export const i16x8_le_u = "~lib/builtins/i16x8.le_u"; + export const i16x8_gt_s = "~lib/builtins/i16x8.gt_s"; + export const i16x8_gt_u = "~lib/builtins/i16x8.gt_u"; + export const i16x8_ge_s = "~lib/builtins/i16x8.ge_s"; + export const i16x8_ge_u = "~lib/builtins/i16x8.ge_u"; + + export const i32x4_splat = "~lib/builtins/i32x4.splat"; + export const i32x4_extract_lane = "~lib/builtins/i32x4.extract_lane"; + export const i32x4_replace_lane = "~lib/builtins/i32x4.replace_lane"; + export const i32x4_add = "~lib/builtins/i32x4.add"; + export const i32x4_sub = "~lib/builtins/i32x4.sub"; + export const i32x4_mul = "~lib/builtins/i32x4.mul"; + export const i32x4_neg = "~lib/builtins/i32x4.neg"; + export const i32x4_shl = "~lib/builtins/i32x4.shl"; + export const i32x4_shr_s = "~lib/builtins/i32x4.shr_s"; + export const i32x4_shr_u = "~lib/builtins/i32x4.shr_u"; + export const i32x4_any_true = "~lib/builtins/i32x4.any_true"; + export const i32x4_all_true = "~lib/builtins/i32x4.all_true"; + export const i32x4_eq = "~lib/builtins/i32x4.eq"; + export const i32x4_ne = "~lib/builtins/i32x4.ne"; + export const i32x4_lt_s = "~lib/builtins/i32x4.lt_s"; + export const i32x4_lt_u = "~lib/builtins/i32x4.lt_u"; + export const i32x4_le_s = "~lib/builtins/i32x4.le_s"; + export const i32x4_le_u = "~lib/builtins/i32x4.le_u"; + export const i32x4_gt_s = "~lib/builtins/i32x4.gt_s"; + export const i32x4_gt_u = "~lib/builtins/i32x4.gt_u"; + export const i32x4_ge_s = "~lib/builtins/i32x4.ge_s"; + export const i32x4_ge_u = "~lib/builtins/i32x4.ge_u"; + export const i32x4_trunc_s_f32x4_sat = "~lib/builtins/i32x4.trunc_s_f32x4_sat"; + export const i32x4_trunc_u_f32x4_sat = "~lib/builtins/i32x4.trunc_u_f32x4_sat"; + + export const i64x2_splat = "~lib/builtins/i64x2.splat"; + export const i64x2_extract_lane = "~lib/builtins/i64x2.extract_lane"; + export const i64x2_replace_lane = "~lib/builtins/i64x2.replace_lane"; + export const i64x2_add = "~lib/builtins/i64x2.add"; + export const i64x2_sub = "~lib/builtins/i64x2.sub"; // i64x2 has no .mul + export const i64x2_neg = "~lib/builtins/i64x2.neg"; + export const i64x2_shl = "~lib/builtins/i64x2.shl"; + export const i64x2_shr_s = "~lib/builtins/i64x2.shr_s"; + export const i64x2_shr_u = "~lib/builtins/i64x2.shr_u"; + export const i64x2_any_true = "~lib/builtins/i64x2.any_true"; + export const i64x2_all_true = "~lib/builtins/i64x2.all_true"; // i64x2 has no .eq etc. + export const i64x2_trunc_s_f64x2_sat = "~lib/builtins/i64x2.trunc_s_f64x2_sat"; + export const i64x2_trunc_u_f64x2_sat = "~lib/builtins/i64x2.trunc_u_f64x2_sat"; + + export const f32x4_splat = "~lib/builtins/f32x4.splat"; + export const f32x4_extract_lane = "~lib/builtins/f32x4.extract_lane"; + export const f32x4_replace_lane = "~lib/builtins/f32x4.replace_lane"; + export const f32x4_add = "~lib/builtins/f32x4.add"; + export const f32x4_sub = "~lib/builtins/f32x4.sub"; + export const f32x4_mul = "~lib/builtins/f32x4.mul"; + export const f32x4_div = "~lib/builtins/f32x4.div"; + export const f32x4_neg = "~lib/builtins/f32x4.neg"; + export const f32x4_min = "~lib/builtins/f32x4.min"; + export const f32x4_max = "~lib/builtins/f32x4.max"; + export const f32x4_abs = "~lib/builtins/f32x4.abs"; + export const f32x4_sqrt = "~lib/builtins/f32x4.sqrt"; + export const f32x4_eq = "~lib/builtins/f32x4.eq"; + export const f32x4_ne = "~lib/builtins/f32x4.ne"; + export const f32x4_lt = "~lib/builtins/f32x4.lt"; + export const f32x4_le = "~lib/builtins/f32x4.le"; + export const f32x4_gt = "~lib/builtins/f32x4.gt"; + export const f32x4_ge = "~lib/builtins/f32x4.ge"; + export const f32x4_convert_s_i32x4 = "~lib/builtins/f32x4.convert_s_i32x4"; + export const f32x4_convert_u_i32x4 = "~lib/builtins/f32x4.convert_u_i32x4"; + + export const f64x2_splat = "~lib/builtins/f64x2.splat"; + export const f64x2_extract_lane = "~lib/builtins/f64x2.extract_lane"; + export const f64x2_replace_lane = "~lib/builtins/f64x2.replace_lane"; + export const f64x2_add = "~lib/builtins/f64x2.add"; + export const f64x2_sub = "~lib/builtins/f64x2.sub"; + export const f64x2_mul = "~lib/builtins/f64x2.mul"; + export const f64x2_div = "~lib/builtins/f64x2.div"; + export const f64x2_neg = "~lib/builtins/f64x2.neg"; + export const f64x2_min = "~lib/builtins/f64x2.min"; + export const f64x2_max = "~lib/builtins/f64x2.max"; + export const f64x2_abs = "~lib/builtins/f64x2.abs"; + export const f64x2_sqrt = "~lib/builtins/f64x2.sqrt"; + export const f64x2_eq = "~lib/builtins/f64x2.eq"; + export const f64x2_ne = "~lib/builtins/f64x2.ne"; + export const f64x2_lt = "~lib/builtins/f64x2.lt"; + export const f64x2_le = "~lib/builtins/f64x2.le"; + export const f64x2_gt = "~lib/builtins/f64x2.gt"; + export const f64x2_ge = "~lib/builtins/f64x2.ge"; + export const f64x2_convert_s_i64x2 = "~lib/builtins/f64x2.convert_s_i64x2"; + export const f64x2_convert_u_i64x2 = "~lib/builtins/f64x2.convert_u_i64x2"; + + export const v8x16_shuffle = "~lib/builtins/v8x16.shuffle"; + // std/diagnostics.ts export const ERROR = "~lib/diagnostics/ERROR"; export const WARNING = "~lib/diagnostics/WARNING"; @@ -1785,8 +1988,8 @@ export function compileCall( // memory access - case BuiltinSymbols.load: { // load(offset: usize, constantOffset?: usize) -> * - if (operands.length < 1 || operands.length > 2) { + case BuiltinSymbols.load: { // load(offset: usize, offset?: usize, align?: usize) -> * + if (operands.length < 1 || operands.length > 3) { if (!(typeArguments && typeArguments.length == 1)) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, @@ -1801,7 +2004,7 @@ export function compileCall( } else { compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, "2", operands.length.toString(10) + reportNode.range, "3", operands.length.toString(10) ); } return module.createUnreachable(); @@ -1820,9 +2023,29 @@ export function compileCall( ConversionKind.IMPLICIT, WrapMode.NONE ); - let offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset - return module.createUnreachable(); + let offset = operands.length >= 2 ? evaluateImmediateOffset(compiler, operands[1]) : 0; // reports + if (offset < 0) return module.createUnreachable(); + let align: i32; + let naturalAlign = typeArguments[0].byteSize; + if (operands.length == 3) { + align = evaluateImmediateOffset(compiler, operands[2]); + if (align < 0) return module.createUnreachable(); + if (align > naturalAlign) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() + ); + return module.createUnreachable(); + } + if (!isPowerOf2(align)) { + compiler.error( + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" + ); + return module.createUnreachable(); + } + } else { + align = naturalAlign; } compiler.currentType = typeArguments[0]; return module.createLoad( @@ -1834,12 +2057,13 @@ export function compileCall( contextualType.size > typeArguments[0].size ? (compiler.currentType = contextualType).toNativeType() : (compiler.currentType = typeArguments[0]).toNativeType(), - offset + offset, + align ); } - case BuiltinSymbols.store: { // store(offset: usize, value: *, constantOffset?: usize) -> void + case BuiltinSymbols.store: { // store(offset: usize, value: *, offset?: usize, align?: usize) -> void compiler.currentType = Type.void; - if (operands.length < 2 || operands.length > 3) { + if (operands.length < 2 || operands.length > 4) { if (!(typeArguments && typeArguments.length == 1)) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, @@ -1854,7 +2078,7 @@ export function compileCall( } else { compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, "3", operands.length.toString(10) + reportNode.range, "4", operands.length.toString(10) ); } return module.createUnreachable(); @@ -1899,14 +2123,34 @@ export function compileCall( } else { type = compiler.currentType; } - let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset - return module.createUnreachable(); + let offset = operands.length >= 3 ? evaluateImmediateOffset(compiler, operands[2]) : 0; // reports + if (offset < 0) return module.createUnreachable(); + let align: i32; + let naturalAlign = typeArguments[0].byteSize; + if (operands.length == 4) { + align = evaluateImmediateOffset(compiler, operands[3]); + if (align < 0) return module.createUnreachable(); + if (align > naturalAlign) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[3].range, "Alignment", "0", naturalAlign.toString() + ); + return module.createUnreachable(); + } + if (!isPowerOf2(align)) { + compiler.error( + DiagnosticCode._0_must_be_a_power_of_two, + operands[3].range, "Alignment" + ); + return module.createUnreachable(); + } + } else { + align = naturalAlign; } compiler.currentType = Type.void; - return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset); + return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset, align); } - case BuiltinSymbols.atomic_load: { // load(offset: usize, constantOffset?: usize) -> * + case BuiltinSymbols.atomic_load: { if (!compiler.options.hasFeature(Feature.THREADS)) break; if (operands.length < 1 || operands.length > 2) { if (!(typeArguments && typeArguments.length == 1)) { @@ -1942,8 +2186,8 @@ export function compileCall( ConversionKind.IMPLICIT, WrapMode.NONE ); - let offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset + let offset = operands.length == 2 ? evaluateImmediateOffset(compiler, operands[1]) : 0; // reports + if (offset < 0) { // reported in evaluateImmediateOffset return module.createUnreachable(); } compiler.currentType = typeArguments[0]; @@ -1958,7 +2202,7 @@ export function compileCall( offset ); } - case BuiltinSymbols.atomic_store: { // store(offset: usize, value: *, constantOffset?: usize) -> void + case BuiltinSymbols.atomic_store: { // store(offset: usize, value: *, immOffset?, immAlign?) -> void if (!compiler.options.hasFeature(Feature.THREADS)) break; compiler.currentType = Type.void; if (operands.length < 2 || operands.length > 3) { @@ -2021,19 +2265,17 @@ export function compileCall( } else { type = compiler.currentType; } - let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset - return module.createUnreachable(); - } + let offset = operands.length == 3 ? evaluateImmediateOffset(compiler, operands[2]) : 0; // reports + if (offset < 0) return module.createUnreachable(); compiler.currentType = Type.void; return module.createAtomicStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset); } - case BuiltinSymbols.atomic_add: // add(ptr: usize, value: T, constantOffset?: usize): T; - case BuiltinSymbols.atomic_sub: // sub(ptr: usize, value: T, constantOffset?: usize): T; - case BuiltinSymbols.atomic_and: // and(ptr: usize, value: T, constantOffset?: usize): T; - case BuiltinSymbols.atomic_or: // or(ptr: usize, value: T, constantOffset?: usize): T; - case BuiltinSymbols.atomic_xor: // xor(ptr: usize, value: T, constantOffset?: usize): T; - case BuiltinSymbols.atomic_xchg: // xchg(ptr: usize, value: T, constantOffset?: usize): T; + case BuiltinSymbols.atomic_add: // add(ptr, value: T, immOffset?: usize): T; + case BuiltinSymbols.atomic_sub: // sub(ptr, value: T, immOffset?: usize): T; + case BuiltinSymbols.atomic_and: // and(ptr, value: T, immOffset?: usize): T; + case BuiltinSymbols.atomic_or: // or(ptr, value: T, immOffset?: usize): T; + case BuiltinSymbols.atomic_xor: // xor(ptr, value: T, immOffset?: usize): T; + case BuiltinSymbols.atomic_xchg: // xchg(ptr, value, immOffset?: usize): T; { if (!compiler.options.hasFeature(Feature.THREADS)) break; if (operands.length < 2 || operands.length > 3) { @@ -2098,10 +2340,8 @@ export function compileCall( type = compiler.currentType; } - let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset - return module.createUnreachable(); - } + let offset = operands.length == 3 ? evaluateImmediateOffset(compiler, operands[2]) : 0; // reports + if (offset < 0) return module.createUnreachable(); let RMWOp: AtomicRMWOp | null = null; switch (prototype.internalName) { case BuiltinSymbols.atomic_add: { RMWOp = AtomicRMWOp.Add; break; } @@ -2203,10 +2443,8 @@ export function compileCall( type = compiler.currentType; } - let offset = operands.length == 4 ? evaluateConstantOffset(compiler, operands[3]) : 0; // reports - if (offset < 0) { // reported in evaluateConstantOffset - return module.createUnreachable(); - } + let offset = operands.length == 4 ? evaluateImmediateOffset(compiler, operands[3]) : 0; // reports + if (offset < 0) return module.createUnreachable(); compiler.currentType = typeArguments[0]; return module.createAtomicCmpxchg( typeArguments[0].byteSize, offset, arg0, arg1, arg2, type.toNativeType() @@ -3352,9 +3590,1850 @@ export function compileCall( WrapMode.NONE ); } - // TODO: v128 - // gc + // === SIMD =================================================================================== + + // const + + case BuiltinSymbols.v128: // alias for now + case BuiltinSymbols.i8x16: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 16) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "16", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 16; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.i8, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.I32); + writeI8(getConstValueI32(expr), bytes, i); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + case BuiltinSymbols.i16x8: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 8) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "8", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 8; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.i16, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.I32); + writeI16(getConstValueI32(expr), bytes, i << 1); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + case BuiltinSymbols.i32x4: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 4) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "4", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.i32, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.I32); + writeI32(getConstValueI32(expr), bytes, i << 2); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + case BuiltinSymbols.i64x2: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.i64, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.I64); + let off = i << 3; + writeI32(getConstValueI64Low(expr), bytes, off); + writeI32(getConstValueI64High(expr), bytes, off + 4); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + case BuiltinSymbols.f32x4: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 4) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "4", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.f32, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.F32); + writeF32(getConstValueF32(expr), bytes, i << 2); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + case BuiltinSymbols.f64x2: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + let bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = module.precomputeExpression( + compiler.compileExpression(value, Type.f64, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(expr) == NativeType.F64); + writeF64(getConstValueF64(expr), bytes, i << 3); + } + } + compiler.currentType = Type.v128; + return module.createV128(bytes); + } + + // v128.* + + case BuiltinSymbols.v128_splat: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = UnaryOp.SplatVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = UnaryOp.SplatVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = UnaryOp.SplatVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = UnaryOp.SplatVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? UnaryOp.SplatVecI64x2 + : UnaryOp.SplatVecI32x4; + break; + } + case TypeKind.F32: { op = UnaryOp.SplatVecF32x4; break; } + case TypeKind.F64: { op = UnaryOp.SplatVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], type, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_extract_lane: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + compiler.currentType = type; + return module.createUnreachable(); + } + let op: SIMDExtractOp; + switch (type.kind) { + case TypeKind.I8: { op = SIMDExtractOp.ExtractLaneSVecI8x16; break; } + case TypeKind.U8: { op = SIMDExtractOp.ExtractLaneUVecI8x16; break; } + case TypeKind.I16: { op = SIMDExtractOp.ExtractLaneSVecI16x8; break; } + case TypeKind.U16: { op = SIMDExtractOp.ExtractLaneUVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = SIMDExtractOp.ExtractLaneVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = SIMDExtractOp.ExtractLaneVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? SIMDExtractOp.ExtractLaneVecI64x2 + : SIMDExtractOp.ExtractLaneVecI32x4; + break; + } + case TypeKind.F32: { op = SIMDExtractOp.ExtractLaneVecF32x4; break; } + case TypeKind.F64: { op = SIMDExtractOp.ExtractLaneVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + compiler.currentType = type; + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = module.precomputeExpression( + compiler.compileExpression(operands[1], Type.u8, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + compiler.currentType = type; + if (getExpressionId(arg1) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + return module.createUnreachable(); + } + assert(getExpressionType(arg1) == NativeType.I32); + let maxIdx = (16 / type.byteSize) - 1; + let idx = getConstValueI32(arg1); + if (idx < 0 || idx > maxIdx) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() + ); + return module.createUnreachable(); + } + return module.createSIMDExtract(op, arg0, idx); + } + case BuiltinSymbols.v128_replace_lane: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 3) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "3", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: SIMDReplaceOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = SIMDReplaceOp.ReplaceLaneVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = SIMDReplaceOp.ReplaceLaneVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = SIMDReplaceOp.ReplaceLaneVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = SIMDReplaceOp.ReplaceLaneVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? SIMDReplaceOp.ReplaceLaneVecI64x2 + : SIMDReplaceOp.ReplaceLaneVecI32x4; + break; + } + case TypeKind.F32: { op = SIMDReplaceOp.ReplaceLaneVecF32x4; break; } + case TypeKind.F64: { op = SIMDReplaceOp.ReplaceLaneVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = module.precomputeExpression( + compiler.compileExpression(operands[1], Type.u8, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(arg1) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(arg1) == NativeType.I32); + let maxIdx = (16 / type.byteSize) - 1; + let idx = getConstValueI32(arg1); + if (idx < 0 || idx > maxIdx) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() + ); + return module.createUnreachable(); + } + arg2 = compiler.compileExpression(operands[2], type, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createSIMDReplace(op, arg0, idx, arg2); + } + case BuiltinSymbols.v128_shuffle: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + compiler.currentType = type; + return module.createUnreachable(); + } + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: + case TypeKind.I64: + case TypeKind.U64: + case TypeKind.ISIZE: + case TypeKind.USIZE: + case TypeKind.F32: + case TypeKind.F64: break; + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + compiler.currentType = type; + return module.createUnreachable(); + } + } + let laneWidth = type.byteSize; + let laneCount = 16 / laneWidth; + if (operands.length != 2 + laneCount) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, (2 + laneCount).toString(), operands.length.toString(10) + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + let mask = new Uint8Array(16); + let maxIdx = (laneCount << 1) - 1; + for (let i = 0; i < laneCount; ++i) { + let operand = operands[2 + i]; + arg2 = module.precomputeExpression( + compiler.compileExpression(operand, Type.u8, ConversionKind.IMPLICIT, WrapMode.NONE) + ); + if (getExpressionId(arg2) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operand.range + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + assert(getExpressionType(arg2) == NativeType.I32); + let idx = getConstValueI32(arg2); + if (idx < 0 || idx > maxIdx) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operand.range, "Lane index", "0", maxIdx.toString() + ); + compiler.currentType = Type.v128; + return module.createUnreachable(); + } + switch (laneWidth) { + case 1: { + writeI8(idx, mask, i); + break; + } + case 2: { + let off8 = i << 1; + let idx8 = idx << 1; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + break; + } + case 4: { + let off8 = i << 2; + let idx8 = idx << 2; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + break; + } + case 8: { + let off8 = i << 3; + let idx8 = idx << 3; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + writeI8(idx8 + 4, mask, off8 + 4); + writeI8(idx8 + 5, mask, off8 + 5); + writeI8(idx8 + 6, mask, off8 + 6); + writeI8(idx8 + 7, mask, off8 + 7); + break; + } + default: assert(false); + } + } + compiler.currentType = Type.v128; + return module.createSIMDShuffle(arg0, arg1, mask); + } + case BuiltinSymbols.v128_add: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = BinaryOp.AddVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = BinaryOp.AddVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = BinaryOp.AddVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = BinaryOp.AddVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.AddVecI64x2 + : BinaryOp.AddVecI32x4; + break; + } + case TypeKind.F32: { op = BinaryOp.AddVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.AddVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_sub: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = BinaryOp.SubVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = BinaryOp.SubVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = BinaryOp.SubVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = BinaryOp.SubVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.SubVecI64x2 + : BinaryOp.SubVecI32x4; + break; + } + case TypeKind.F32: { op = BinaryOp.SubVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.SubVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_mul: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = BinaryOp.MulVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = BinaryOp.MulVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = BinaryOp.MulVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.MulVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.MulVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = BinaryOp.MulVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_div: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.F32: { op = BinaryOp.DivVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.DivVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_neg: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = UnaryOp.NegVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = UnaryOp.NegVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = UnaryOp.NegVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = UnaryOp.NegVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? UnaryOp.NegVecI64x2 + : UnaryOp.NegVecI32x4; + break; + } + case TypeKind.F32: { op = UnaryOp.NegVecF32x4; break; } + case TypeKind.F64: { op = UnaryOp.NegVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_add_saturate: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.AddSatSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.AddSatUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.AddSatSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.AddSatUVecI16x8; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_sub_saturate: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.SubSatSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.SubSatUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.SubSatSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.SubSatUVecI16x8; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_shl: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: SIMDShiftOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = SIMDShiftOp.ShlVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = SIMDShiftOp.ShlVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = SIMDShiftOp.ShlVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = SIMDShiftOp.ShlVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? SIMDShiftOp.ShlVecI64x2 + : SIMDShiftOp.ShlVecI32x4; + break; + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.i32, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createSIMDShift(op, arg0, arg1); + } + case BuiltinSymbols.v128_shr: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: SIMDShiftOp; + switch (type.kind) { + case TypeKind.I8: { op = SIMDShiftOp.ShrSVecI8x16; break; } + case TypeKind.U8: { op = SIMDShiftOp.ShrUVecI8x16; break; } + case TypeKind.I16: { op = SIMDShiftOp.ShrSVecI16x8; break; } + case TypeKind.U16: { op = SIMDShiftOp.ShrUVecI16x8; break; } + case TypeKind.I32: { op = SIMDShiftOp.ShrSVecI32x4; break; } + case TypeKind.U32: { op = SIMDShiftOp.ShrUVecI32x4; break; } + case TypeKind.I64: { op = SIMDShiftOp.ShrSVecI64x2; break; } + case TypeKind.U64: { op = SIMDShiftOp.ShrUVecI64x2; break; } + case TypeKind.ISIZE: { + op = compiler.options.isWasm64 + ? SIMDShiftOp.ShrSVecI64x2 + : SIMDShiftOp.ShrSVecI32x4; + break; + } + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? SIMDShiftOp.ShrUVecI64x2 + : SIMDShiftOp.ShrUVecI32x4; + break; + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.i32, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createSIMDShift(op, arg0, arg1); + } + case BuiltinSymbols.v128_and: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(BinaryOp.AndVec128, arg0, arg1); + } + case BuiltinSymbols.v128_or: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(BinaryOp.OrVec128, arg0, arg1); + } + case BuiltinSymbols.v128_xor: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(BinaryOp.XorVec128, arg0, arg1); + } + case BuiltinSymbols.v128_not: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(UnaryOp.NotVec128, arg0); + } + case BuiltinSymbols.v128_bitselect: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (typeArguments) { + compiler.error( + DiagnosticCode.Type_0_is_not_generic, + reportNode.range, prototype.internalName + ); + } + if (operands.length != 3) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "3", operands.length.toString(10) + ); + return module.createUnreachable(); + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg2 = compiler.compileExpression(operands[2], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createSIMDBitselect(arg0, arg1, arg2); + } + case BuiltinSymbols.v128_any_true: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.bool; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = UnaryOp.AnyTrueVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = UnaryOp.AnyTrueVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = UnaryOp.AnyTrueVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = UnaryOp.AnyTrueVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? UnaryOp.AnyTrueVecI64x2 + : UnaryOp.AnyTrueVecI32x4; + break; + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.bool; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_all_true: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.bool; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = UnaryOp.AllTrueVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = UnaryOp.AllTrueVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = UnaryOp.AllTrueVecI32x4; break; } + case TypeKind.I64: + case TypeKind.U64: { op = UnaryOp.AllTrueVecI64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? UnaryOp.AllTrueVecI64x2 + : UnaryOp.AllTrueVecI32x4; + break; + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.bool; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_min: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.F32: { op = BinaryOp.MinVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.MinVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_max: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.F32: { op = BinaryOp.MaxVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.MaxVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_abs: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.F32: { op = UnaryOp.AbsVecF32x4; break; } + case TypeKind.F64: { op = UnaryOp.AbsVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_sqrt: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (type.kind) { + case TypeKind.F32: { op = UnaryOp.SqrtVecF32x4; break; } + case TypeKind.F64: { op = UnaryOp.SqrtVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_eq: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = BinaryOp.EqVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = BinaryOp.EqVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = BinaryOp.EqVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.EqVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.EqVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = BinaryOp.EqVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_ne: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { op = BinaryOp.NeVecI8x16; break; } + case TypeKind.I16: + case TypeKind.U16: { op = BinaryOp.NeVecI16x8; break; } + case TypeKind.I32: + case TypeKind.U32: { op = BinaryOp.NeVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.NeVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.NeVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = BinaryOp.NeVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_lt: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.LtSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.LtUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.LtSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.LtUVecI16x8; break; } + case TypeKind.I32: { op = BinaryOp.LtSVecI32x4; break; } + case TypeKind.U32: { op = BinaryOp.LtUVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.LtVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.LtVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = type.kind == TypeKind.ISIZE + ? BinaryOp.LtSVecI32x4 + : BinaryOp.LtUVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_le: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.LeSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.LeUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.LeSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.LeUVecI16x8; break; } + case TypeKind.I32: { op = BinaryOp.LeSVecI32x4; break; } + case TypeKind.U32: { op = BinaryOp.LeUVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.LeVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.LeVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = type.kind == TypeKind.ISIZE + ? BinaryOp.LeSVecI32x4 + : BinaryOp.LeUVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_gt: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.GtSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.GtUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.GtSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.GtUVecI16x8; break; } + case TypeKind.I32: { op = BinaryOp.GtSVecI32x4; break; } + case TypeKind.U32: { op = BinaryOp.GtUVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.GtVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.GtVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = type.kind == TypeKind.ISIZE + ? BinaryOp.GtSVecI32x4 + : BinaryOp.GtUVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_ge: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 2) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "2", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let type = typeArguments[0]; + if (!type.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: BinaryOp; + switch (type.kind) { + case TypeKind.I8: { op = BinaryOp.GeSVecI8x16; break; } + case TypeKind.U8: { op = BinaryOp.GeUVecI8x16; break; } + case TypeKind.I16: { op = BinaryOp.GeSVecI16x8; break; } + case TypeKind.U16: { op = BinaryOp.GeUVecI16x8; break; } + case TypeKind.I32: { op = BinaryOp.GeSVecI32x4; break; } + case TypeKind.U32: { op = BinaryOp.GeUVecI32x4; break; } + case TypeKind.F32: { op = BinaryOp.GeVecF32x4; break; } + case TypeKind.F64: { op = BinaryOp.GeVecF64x2; break; } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + op = type.kind == TypeKind.ISIZE + ? BinaryOp.GeSVecI32x4 + : BinaryOp.GeUVecI32x4; + break; + } + } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + arg1 = compiler.compileExpression(operands[1], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createBinary(op, arg0, arg1); + } + case BuiltinSymbols.v128_convert: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let fromType = typeArguments[0]; + if (!fromType.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (fromType.kind) { + case TypeKind.I32: { op = UnaryOp.ConvertSVecI32x4ToVecF32x4; break; } + case TypeKind.U32: { op = UnaryOp.ConvertUVecI32x4ToVecF32x4; break; } + case TypeKind.I64: { op = UnaryOp.ConvertSVecI64x2ToVecF64x2; break; } + case TypeKind.U64: { op = UnaryOp.ConvertUVecI64x2ToVecF64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + case BuiltinSymbols.v128_trunc: { + if (!compiler.options.hasFeature(Feature.SIMD)) break; + compiler.currentType = Type.v128; + if (!(typeArguments && typeArguments.length == 1)) { + compiler.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + reportNode.range, "1", typeArguments ? typeArguments.length.toString() : "0" + ); + return module.createUnreachable(); + } + if (operands.length != 1) { + compiler.error( + DiagnosticCode.Expected_0_arguments_but_got_1, + reportNode.range, "1", operands.length.toString(10) + ); + return module.createUnreachable(); + } + let toType = typeArguments[0]; + if (!toType.is(TypeFlags.VALUE)) { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + let op: UnaryOp; + switch (toType.kind) { + case TypeKind.I32: { op = UnaryOp.TruncSatSVecF32x4ToVecI32x4; break; } + case TypeKind.U32: { op = UnaryOp.TruncSatUVecF32x4ToVecI32x4; break; } + case TypeKind.I64: { op = UnaryOp.TruncSatSVecF64x2ToVecI64x2; break; } + case TypeKind.U64: { op = UnaryOp.TruncSatUVecF64x2ToVecI64x2; break; } + default: { + compiler.error( + DiagnosticCode.Operation_not_supported, + reportNode.range + ); + return module.createUnreachable(); + } + } + arg0 = compiler.compileExpression(operands[0], Type.v128, ConversionKind.IMPLICIT, WrapMode.NONE); + compiler.currentType = Type.v128; + return module.createUnary(op, arg0); + } + + // === GC integration ========================================================================= case BuiltinSymbols.iterateRoots: { if (typeArguments) { @@ -3393,9 +5472,11 @@ export function compileCall( return module.createCall("~iterateRoots", [ expr ], NativeType.None); } } - var expr = deferASMCall(compiler, prototype, operands, contextualType, reportNode); + + // try to defer inline asm to a concrete built-in + var expr = tryDeferASM(compiler, prototype, operands, reportNode); if (expr) { - if (typeArguments && typeArguments.length) { + if (typeArguments) { compiler.error( DiagnosticCode.Type_0_is_not_generic, reportNode.range, prototype.internalName @@ -3410,12 +5491,11 @@ export function compileCall( return module.createUnreachable(); } -/** Defers an inline-assembler-like call to a built-in function. */ -function deferASMCall( +/** Tries to defer an inline-assembler-like call to a built-in function. */ +function tryDeferASM( compiler: Compiler, prototype: FunctionPrototype, operands: Expression[], - contextualType: Type, reportNode: CallExpression ): ExpressionRef { /* tslint:disable:max-line-length */ @@ -3484,6 +5564,7 @@ function deferASMCall( } if (compiler.options.hasFeature(Feature.THREADS)) { switch (prototype.internalName) { + case BuiltinSymbols.i32_atomic_load8_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_load16_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u16, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_load: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.i32, operands, Type.i32, reportNode); @@ -3491,6 +5572,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_load16_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_load32_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_load: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.i64, operands, Type.i64, reportNode); + case BuiltinSymbols.i32_atomic_store8: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i8, operands, Type.i32, reportNode); case BuiltinSymbols.i32_atomic_store16: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i16, operands, Type.i32, reportNode); case BuiltinSymbols.i32_atomic_store: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i32, operands, Type.i32, reportNode); @@ -3498,6 +5580,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_store16: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i16, operands, Type.i64, reportNode); case BuiltinSymbols.i64_atomic_store32: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i32, operands, Type.i64, reportNode); case BuiltinSymbols.i64_atomic_store: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i64, operands, Type.i64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u16, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u32, operands, Type.u32, reportNode); @@ -3505,6 +5588,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u16, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u32, operands, Type.u32, reportNode); @@ -3512,6 +5596,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u16, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u32, operands, Type.u32, reportNode); @@ -3519,6 +5604,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u16, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u32, operands, Type.u32, reportNode); @@ -3526,6 +5612,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode); @@ -3533,6 +5620,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode); @@ -3540,6 +5628,7 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_atomic_rmw8_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw16_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode); case BuiltinSymbols.i32_atomic_rmw_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode); @@ -3547,12 +5636,159 @@ function deferASMCall( case BuiltinSymbols.i64_atomic_rmw16_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u16, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw32_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u32, operands, Type.u64, reportNode); case BuiltinSymbols.i64_atomic_rmw_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u64, operands, Type.u64, reportNode); + case BuiltinSymbols.i32_wait: return deferASM(BuiltinSymbols.atomic_wait, compiler, Type.i32, operands, Type.u32, reportNode); case BuiltinSymbols.i64_wait: return deferASM(BuiltinSymbols.atomic_wait, compiler, Type.i64, operands, Type.i64, reportNode); case BuiltinSymbols.i32_notify: return deferASM(BuiltinSymbols.atomic_notify, compiler, Type.i32, operands, Type.u32, reportNode); case BuiltinSymbols.i64_notify: return deferASM(BuiltinSymbols.atomic_notify, compiler, Type.i64, operands, Type.i64, reportNode); } } + if (compiler.options.hasFeature(Feature.SIMD)) { + switch (prototype.internalName) { + + case BuiltinSymbols.v128_load: return deferASM(BuiltinSymbols.load, compiler, Type.v128, operands, Type.v128, reportNode); + case BuiltinSymbols.v128_store: return deferASM(BuiltinSymbols.store, compiler, Type.v128, operands, Type.void, reportNode); + + case BuiltinSymbols.i8x16_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_extract_lane_s: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.i8, operands, Type.i8, reportNode); + case BuiltinSymbols.i8x16_extract_lane_u: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.u8, operands, Type.u8, reportNode); + case BuiltinSymbols.i8x16_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_mul: return deferASM(BuiltinSymbols.v128_mul, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_add_saturate_s: return deferASM(BuiltinSymbols.v128_add_saturate, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_add_saturate_u: return deferASM(BuiltinSymbols.v128_add_saturate, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_sub_saturate_s: return deferASM(BuiltinSymbols.v128_sub_saturate, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_sub_saturate_u: return deferASM(BuiltinSymbols.v128_sub_saturate, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_shl: return deferASM(BuiltinSymbols.v128_shl, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_shr_s: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_shr_u: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_any_true: return deferASM(BuiltinSymbols.v128_any_true, compiler, Type.i8, operands, Type.i32, reportNode); + case BuiltinSymbols.i8x16_all_true: return deferASM(BuiltinSymbols.v128_all_true, compiler, Type.i8, operands, Type.i32, reportNode); + case BuiltinSymbols.i8x16_eq: return deferASM(BuiltinSymbols.v128_eq, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_ne: return deferASM(BuiltinSymbols.v128_ne, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_lt_s: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_lt_u: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_le_s: return deferASM(BuiltinSymbols.v128_le, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_le_u: return deferASM(BuiltinSymbols.v128_le, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_gt_s: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_gt_u: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.u8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_ge_s: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.i8, operands, Type.v128, reportNode); + case BuiltinSymbols.i8x16_ge_u: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.u8, operands, Type.v128, reportNode); + + case BuiltinSymbols.i16x8_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_extract_lane_s: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.i16, operands, Type.i16, reportNode); + case BuiltinSymbols.i16x8_extract_lane_u: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.u16, operands, Type.u16, reportNode); + case BuiltinSymbols.i16x8_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_mul: return deferASM(BuiltinSymbols.v128_mul, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_add_saturate_s: return deferASM(BuiltinSymbols.v128_add_saturate, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_add_saturate_u: return deferASM(BuiltinSymbols.v128_add_saturate, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_sub_saturate_s: return deferASM(BuiltinSymbols.v128_sub_saturate, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_sub_saturate_u: return deferASM(BuiltinSymbols.v128_sub_saturate, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_shl: return deferASM(BuiltinSymbols.v128_shl, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_shr_s: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_shr_u: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_any_true: return deferASM(BuiltinSymbols.v128_any_true, compiler, Type.i16, operands, Type.i32, reportNode); + case BuiltinSymbols.i16x8_all_true: return deferASM(BuiltinSymbols.v128_all_true, compiler, Type.i16, operands, Type.i32, reportNode); + case BuiltinSymbols.i16x8_eq: return deferASM(BuiltinSymbols.v128_eq, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_ne: return deferASM(BuiltinSymbols.v128_ne, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_lt_s: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_lt_u: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_le_s: return deferASM(BuiltinSymbols.v128_le, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_le_u: return deferASM(BuiltinSymbols.v128_le, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_gt_s: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_gt_u: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.u16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_ge_s: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.i16, operands, Type.v128, reportNode); + case BuiltinSymbols.i16x8_ge_u: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.u16, operands, Type.v128, reportNode); + + case BuiltinSymbols.i32x4_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_extract_lane: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.i32, operands, Type.i32, reportNode); + case BuiltinSymbols.i32x4_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_mul: return deferASM(BuiltinSymbols.v128_mul, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_shl: return deferASM(BuiltinSymbols.v128_shl, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_shr_s: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_shr_u: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.u32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_any_true: return deferASM(BuiltinSymbols.v128_any_true, compiler, Type.i32, operands, Type.i32, reportNode); + case BuiltinSymbols.i32x4_all_true: return deferASM(BuiltinSymbols.v128_all_true, compiler, Type.i32, operands, Type.i32, reportNode); + case BuiltinSymbols.i32x4_eq: return deferASM(BuiltinSymbols.v128_eq, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_ne: return deferASM(BuiltinSymbols.v128_ne, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_lt_s: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_lt_u: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.u32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_le_s: return deferASM(BuiltinSymbols.v128_le, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_le_u: return deferASM(BuiltinSymbols.v128_le, compiler, Type.u32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_gt_s: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_gt_u: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.u32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_ge_s: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_ge_u: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.u32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_trunc_s_f32x4_sat: return deferASM(BuiltinSymbols.v128_trunc, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.i32x4_trunc_u_f32x4_sat: return deferASM(BuiltinSymbols.v128_trunc, compiler, Type.u32, operands, Type.v128, reportNode); + + case BuiltinSymbols.i64x2_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_extract_lane: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.i64, operands, Type.i64, reportNode); + case BuiltinSymbols.i64x2_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_shl: return deferASM(BuiltinSymbols.v128_shl, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_shr_s: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_shr_u: return deferASM(BuiltinSymbols.v128_shr, compiler, Type.u64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_any_true: return deferASM(BuiltinSymbols.v128_any_true, compiler, Type.i64, operands, Type.i32, reportNode); + case BuiltinSymbols.i64x2_all_true: return deferASM(BuiltinSymbols.v128_all_true, compiler, Type.i64, operands, Type.i32, reportNode); + case BuiltinSymbols.i64x2_trunc_s_f64x2_sat: return deferASM(BuiltinSymbols.v128_trunc, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.i64x2_trunc_u_f64x2_sat: return deferASM(BuiltinSymbols.v128_trunc, compiler, Type.u64, operands, Type.v128, reportNode); + + case BuiltinSymbols.f32x4_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_extract_lane: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.f32, operands, Type.f32, reportNode); + case BuiltinSymbols.f32x4_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_mul: return deferASM(BuiltinSymbols.v128_mul, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_div: return deferASM(BuiltinSymbols.v128_div, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_min: return deferASM(BuiltinSymbols.v128_min, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_max: return deferASM(BuiltinSymbols.v128_max, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_abs: return deferASM(BuiltinSymbols.v128_abs, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_sqrt: return deferASM(BuiltinSymbols.v128_sqrt, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_eq: return deferASM(BuiltinSymbols.v128_eq, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_ne: return deferASM(BuiltinSymbols.v128_ne, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_lt: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_le: return deferASM(BuiltinSymbols.v128_le, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_gt: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_ge: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.f32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_convert_s_i32x4: return deferASM(BuiltinSymbols.v128_convert, compiler, Type.i32, operands, Type.v128, reportNode); + case BuiltinSymbols.f32x4_convert_u_i32x4: return deferASM(BuiltinSymbols.v128_convert, compiler, Type.u32, operands, Type.v128, reportNode); + + case BuiltinSymbols.f64x2_splat: return deferASM(BuiltinSymbols.v128_splat, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_extract_lane: return deferASM(BuiltinSymbols.v128_extract_lane, compiler, Type.f64, operands, Type.f64, reportNode); + case BuiltinSymbols.f64x2_replace_lane: return deferASM(BuiltinSymbols.v128_replace_lane, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_add: return deferASM(BuiltinSymbols.v128_add, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_sub: return deferASM(BuiltinSymbols.v128_sub, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_mul: return deferASM(BuiltinSymbols.v128_mul, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_div: return deferASM(BuiltinSymbols.v128_div, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_neg: return deferASM(BuiltinSymbols.v128_neg, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_min: return deferASM(BuiltinSymbols.v128_min, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_max: return deferASM(BuiltinSymbols.v128_max, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_abs: return deferASM(BuiltinSymbols.v128_abs, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_sqrt: return deferASM(BuiltinSymbols.v128_sqrt, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_eq: return deferASM(BuiltinSymbols.v128_eq, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_ne: return deferASM(BuiltinSymbols.v128_ne, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_lt: return deferASM(BuiltinSymbols.v128_lt, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_le: return deferASM(BuiltinSymbols.v128_le, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_gt: return deferASM(BuiltinSymbols.v128_gt, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_ge: return deferASM(BuiltinSymbols.v128_ge, compiler, Type.f64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_convert_s_i64x2: return deferASM(BuiltinSymbols.v128_convert, compiler, Type.i64, operands, Type.v128, reportNode); + case BuiltinSymbols.f64x2_convert_u_i64x2: return deferASM(BuiltinSymbols.v128_convert, compiler, Type.u64, operands, Type.v128, reportNode); + + case BuiltinSymbols.v8x16_shuffle: return deferASM(BuiltinSymbols.v128_shuffle, compiler, Type.i8, operands, Type.v128, reportNode); + } + } /* tslint:enable:max-line-length */ return 0; } @@ -3621,8 +5857,8 @@ function evaluateConstantType( return null; } -/** Evaluates a `constantOffset` argument.*/ -function evaluateConstantOffset(compiler: Compiler, expression: Expression): i32 { +/** Evaluates a compile-time constant immediate offset argument.*/ +function evaluateImmediateOffset(compiler: Compiler, expression: Expression): i32 { var expr: ExpressionRef; var value: i32; if (compiler.options.isWasm64) { diff --git a/src/common.ts b/src/common.ts index 728fe00c..e2518b28 100644 --- a/src/common.ts +++ b/src/common.ts @@ -118,6 +118,16 @@ export namespace CommonSymbols { export const f32 = "f32"; export const f64 = "f64"; export const v128 = "v128"; + export const i8x16 = "i8x16"; + export const u8x16 = "u8x16"; + export const i16x8 = "i16x8"; + export const u16x8 = "u16x8"; + export const i32x4 = "i32x4"; + export const u32x4 = "u32x4"; + export const i64x2 = "i64x2"; + export const u64x2 = "u64x2"; + export const f32x4 = "f32x4"; + export const f64x2 = "f64x2"; export const void_ = "void"; export const number = "number"; export const boolean = "boolean"; @@ -146,6 +156,7 @@ export namespace LibrarySymbols { export const ASC_FEATURE_SIGN_EXTENSION = "ASC_FEATURE_SIGN_EXTENSION"; export const ASC_FEATURE_BULK_MEMORY = "ASC_FEATURE_BULK_MEMORY"; export const ASC_FEATURE_SIMD = "ASC_FEATURE_SIMD"; + export const ASC_FEATURE_THREADS = "ASC_FEATURE_THREADS"; // classes export const I8 = "I8"; export const I16 = "I16"; diff --git a/src/compiler.ts b/src/compiler.ts index 139d688e..7f4022f7 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -3199,6 +3199,12 @@ export class Compiler extends DiagnosticEmitter { expr = module.createBinary(BinaryOp.EqF64, leftExpr, rightExpr); break; } + case TypeKind.V128: { + expr = module.createUnary(UnaryOp.AllTrueVecI8x16, + module.createBinary(BinaryOp.EqVecI8x16, leftExpr, rightExpr) + ); + break; + } default: { assert(false); expr = module.createUnreachable(); @@ -3287,6 +3293,12 @@ export class Compiler extends DiagnosticEmitter { expr = module.createBinary(BinaryOp.NeF64, leftExpr, rightExpr); break; } + case TypeKind.V128: { + expr = module.createUnary(UnaryOp.AnyTrueVecI8x16, + module.createBinary(BinaryOp.NeVecI8x16, leftExpr, rightExpr) + ); + break; + } default: { assert(false); expr = module.createUnreachable(); diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 99e9c3d4..dd8d4512 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -32,6 +32,8 @@ export enum DiagnosticCode { Optional_properties_are_not_supported = 219, Expression_must_be_a_compile_time_constant = 220, Module_cannot_have_multiple_start_functions = 221, + _0_must_be_a_value_between_1_and_2_inclusive = 222, + _0_must_be_a_power_of_two = 223, Unterminated_string_literal = 1002, Identifier_expected = 1003, _0_expected = 1005, @@ -165,6 +167,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 219: return "Optional properties are not supported."; case 220: return "Expression must be a compile-time constant."; case 221: return "Module cannot have multiple start functions."; + case 222: return "'{0}' must be a value between '{1}' and '{2}' inclusive."; + case 223: return "'{0}' must be a power of two."; case 1002: return "Unterminated string literal."; case 1003: return "Identifier expected."; case 1005: return "'{0}' expected."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 041c578b..12806277 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -24,6 +24,8 @@ "Optional properties are not supported.": 219, "Expression must be a compile-time constant.": 220, "Module cannot have multiple start functions.": 221, + "'{0}' must be a value between '{1}' and '{2}' inclusive.": 222, + "'{0}' must be a power of two.": 223, "Unterminated string literal.": 1002, "Identifier expected.": 1003, diff --git a/src/flow.ts b/src/flow.ts index 597a1e25..ceae0a1b 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -232,6 +232,7 @@ export class Flow { case NativeType.I64: { temps = parentFunction.tempI64s; break; } case NativeType.F32: { temps = parentFunction.tempF32s; break; } case NativeType.F64: { temps = parentFunction.tempF64s; break; } + case NativeType.V128: { temps = parentFunction.tempV128s; break; } default: throw new Error("concrete type expected"); } var local: Local; @@ -270,6 +271,10 @@ export class Flow { temps = parentFunction.tempF64s || (parentFunction.tempF64s = []); break; } + case NativeType.V128: { + temps = parentFunction.tempV128s || (parentFunction.tempV128s = []); + break; + } default: throw new Error("concrete type expected"); } assert(local.index >= 0); @@ -297,6 +302,10 @@ export class Flow { temps = parentFunction.tempF64s || (parentFunction.tempF64s = []); break; } + case NativeType.V128: { + temps = parentFunction.tempV128s || (parentFunction.tempV128s = []); + break; + } default: throw new Error("concrete type expected"); } var local: Local; diff --git a/src/module.ts b/src/module.ts index 78842a3f..cced3216 100644 --- a/src/module.ts +++ b/src/module.ts @@ -122,7 +122,7 @@ export enum UnaryOp { ExtendI16ToI32 = _BinaryenExtendS16Int32(), ExtendI8ToI64 = _BinaryenExtendS8Int64(), ExtendI16ToI64 = _BinaryenExtendS16Int64(), - ExtendI32ToI64 = _BinaryenExtendS32Int64() + ExtendI32ToI64 = _BinaryenExtendS32Int64(), // see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions // TruncF32ToI32Sat @@ -133,6 +133,41 @@ export enum UnaryOp { // TruncF32ToU64Sat // TruncF64ToI64Sat // TruncF64ToU64Sat + + // see: https://github.com/WebAssembly/simd + SplatVecI8x16 = _BinaryenSplatVecI8x16(), + SplatVecI16x8 = _BinaryenSplatVecI16x8(), + SplatVecI32x4 = _BinaryenSplatVecI32x4(), + SplatVecI64x2 = _BinaryenSplatVecI64x2(), + SplatVecF32x4 = _BinaryenSplatVecF32x4(), + SplatVecF64x2 = _BinaryenSplatVecF64x2(), + NotVec128 = _BinaryenNotVec128(), + NegVecI8x16 = _BinaryenNegVecI8x16(), + AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(), + AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(), + NegVecI16x8 = _BinaryenNegVecI16x8(), + AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(), + AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(), + NegVecI32x4 = _BinaryenNegVecI32x4(), + AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(), + AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(), + NegVecI64x2 = _BinaryenNegVecI64x2(), + AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(), + AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(), + AbsVecF32x4 = _BinaryenAbsVecF32x4(), + NegVecF32x4 = _BinaryenNegVecF32x4(), + SqrtVecF32x4 = _BinaryenSqrtVecF32x4(), + AbsVecF64x2 = _BinaryenAbsVecF64x2(), + NegVecF64x2 = _BinaryenNegVecF64x2(), + SqrtVecF64x2 = _BinaryenSqrtVecF64x2(), + TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(), + TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(), + TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(), + TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(), + ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(), + ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(), + ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(), + ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2() } export enum BinaryOp { @@ -211,61 +246,9 @@ export enum BinaryOp { LtF64 = _BinaryenLtFloat64(), LeF64 = _BinaryenLeFloat64(), GtF64 = _BinaryenGtFloat64(), - GeF64 = _BinaryenGeFloat64() -} + GeF64 = _BinaryenGeFloat64(), -export enum HostOp { - CurrentMemory = _BinaryenCurrentMemory(), - GrowMemory = _BinaryenGrowMemory(), - - // see: https://github.com/WebAssembly/bulk-memory-operations - // MoveMemory - // SetMemory -} - -export enum AtomicRMWOp { - Add = _BinaryenAtomicRMWAdd(), - Sub = _BinaryenAtomicRMWSub(), - And = _BinaryenAtomicRMWAnd(), - Or = _BinaryenAtomicRMWOr(), - Xor = _BinaryenAtomicRMWXor(), - Xchg = _BinaryenAtomicRMWXchg() -} - -export enum SIMDOp { - SplatVecI8x16 = _BinaryenSplatVecI8x16(), - SplatVecI16x8 = _BinaryenSplatVecI16x8(), - SplatVecI32x4 = _BinaryenSplatVecI32x4(), - SplatVecI64x2 = _BinaryenSplatVecI64x2(), - SplatVecF32x4 = _BinaryenSplatVecF32x4(), - SplatVecF64x2 = _BinaryenSplatVecF64x2(), - NotVec128 = _BinaryenNotVec128(), - NegVecI8x16 = _BinaryenNegVecI8x16(), - AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(), - AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(), - NegVecI16x8 = _BinaryenNegVecI16x8(), - AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(), - AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(), - NegVecI32x4 = _BinaryenNegVecI32x4(), - AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(), - AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(), - NegVecI64x2 = _BinaryenNegVecI64x2(), - AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(), - AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(), - AbsVecF32x4 = _BinaryenAbsVecF32x4(), - NegVecF32x4 = _BinaryenNegVecF32x4(), - SqrtVecF32x4 = _BinaryenSqrtVecF32x4(), - AbsVecF64x2 = _BinaryenAbsVecF64x2(), - NegVecF64x2 = _BinaryenNegVecF64x2(), - SqrtVecF64x2 = _BinaryenSqrtVecF64x2(), - TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(), - TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(), - TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(), - TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(), - ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(), - ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(), - ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(), - ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2(), + // see: https://github.com/WebAssembly/simd EqVecI8x16 = _BinaryenEqVecI8x16(), NeVecI8x16 = _BinaryenNeVecI8x16(), LtSVecI8x16 = _BinaryenLtSVecI8x16(), @@ -344,6 +327,59 @@ export enum SIMDOp { MaxVecF64x2 = _BinaryenMaxVecF64x2() } +export enum HostOp { + CurrentMemory = _BinaryenCurrentMemory(), + GrowMemory = _BinaryenGrowMemory(), + + // see: https://github.com/WebAssembly/bulk-memory-operations + // MoveMemory + // SetMemory +} + +export enum AtomicRMWOp { + Add = _BinaryenAtomicRMWAdd(), + Sub = _BinaryenAtomicRMWSub(), + And = _BinaryenAtomicRMWAnd(), + Or = _BinaryenAtomicRMWOr(), + Xor = _BinaryenAtomicRMWXor(), + Xchg = _BinaryenAtomicRMWXchg() +} + +export enum SIMDExtractOp { + ExtractLaneSVecI8x16 = _BinaryenExtractLaneSVecI8x16(), + ExtractLaneUVecI8x16 = _BinaryenExtractLaneUVecI8x16(), + ExtractLaneSVecI16x8 = _BinaryenExtractLaneSVecI16x8(), + ExtractLaneUVecI16x8 = _BinaryenExtractLaneUVecI16x8(), + ExtractLaneVecI32x4 = _BinaryenExtractLaneVecI32x4(), + ExtractLaneVecI64x2 = _BinaryenExtractLaneVecI64x2(), + ExtractLaneVecF32x4 = _BinaryenExtractLaneVecF32x4(), + ExtractLaneVecF64x2 = _BinaryenExtractLaneVecF64x2(), +} + +export enum SIMDReplaceOp { + ReplaceLaneVecI8x16 = _BinaryenReplaceLaneVecI8x16(), + ReplaceLaneVecI16x8 = _BinaryenReplaceLaneVecI16x8(), + ReplaceLaneVecI32x4 = _BinaryenReplaceLaneVecI32x4(), + ReplaceLaneVecI64x2 = _BinaryenReplaceLaneVecI64x2(), + ReplaceLaneVecF32x4 = _BinaryenReplaceLaneVecF32x4(), + ReplaceLaneVecF64x2 = _BinaryenReplaceLaneVecF64x2() +} + +export enum SIMDShiftOp { // FIXME: seems to be missing in binaryen-c.h + ShlVecI8x16, + ShrSVecI8x16, + ShrUVecI8x16, + ShlVecI16x8, + ShrSVecI16x8, + ShrUVecI16x8, + ShlVecI32x4, + ShrSVecI32x4, + ShrUVecI32x4, + ShlVecI64x2, + ShrSVecI64x2, + ShrUVecI64x2 +} + export class MemorySegment { buffer: Uint8Array; @@ -510,9 +546,10 @@ export class Module { signed: bool, ptr: ExpressionRef, type: NativeType, - offset: Index = 0 + offset: Index = 0, + align: Index = bytes // naturally aligned by default ): ExpressionRef { - return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, /* always aligned */ bytes, type, ptr); + return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, ptr); } createStore( @@ -520,9 +557,10 @@ export class Module { ptr: ExpressionRef, value: ExpressionRef, type: NativeType, - offset: Index = 0 + offset: Index = 0, + align: Index = bytes // naturally aligned by default ): ExpressionRef { - return _BinaryenStore(this.ref, bytes, offset, /* always aligned */ bytes, ptr, value, type); + return _BinaryenStore(this.ref, bytes, offset, align, ptr, value, type); } createAtomicLoad( @@ -732,6 +770,55 @@ export class Module { return _BinaryenMemoryFill(this.ref, dest, value, size); } + // simd + + createSIMDExtract( + op: SIMDExtractOp, + vec: ExpressionRef, + idx: u8 + ): ExpressionRef { + return _BinaryenSIMDExtract(this.ref, op, vec, idx); + } + + createSIMDReplace( + op: SIMDReplaceOp, + vec: ExpressionRef, + idx: u8, + value: ExpressionRef + ): ExpressionRef { + return _BinaryenSIMDReplace(this.ref, op, vec, idx, value); + } + + createSIMDShuffle( + vec1: ExpressionRef, + vec2: ExpressionRef, + mask: Uint8Array + ): ExpressionRef { + assert(mask.length == 16); + var cArr = allocU8Array(mask); + try { + return _BinaryenSIMDShuffle(this.ref, vec1, vec2, cArr); + } finally { + memory.free(cArr); + } + } + + createSIMDBitselect( + vec1: ExpressionRef, + vec2: ExpressionRef, + cond: ExpressionRef + ): ExpressionRef { + return _BinaryenSIMDBitselect(this.ref, vec1, vec2, cond); + } + + createSIMDShift( + op: SIMDShiftOp, + vec: ExpressionRef, + shift: ExpressionRef + ): ExpressionRef { + return _BinaryenSIMDShift(this.ref, op, vec, shift); + } + // meta addGlobal( diff --git a/src/program.ts b/src/program.ts index a771eac2..fee9a60a 100644 --- a/src/program.ts +++ b/src/program.ts @@ -523,6 +523,8 @@ export class Program extends DiagnosticEmitter { i64_new(options.hasFeature(Feature.BULK_MEMORY) ? 1 : 0, 0)); this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_SIMD, Type.bool, i64_new(options.hasFeature(Feature.SIMD) ? 1 : 0, 0)); + this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_THREADS, Type.bool, + i64_new(options.hasFeature(Feature.THREADS) ? 1 : 0, 0)); // remember deferred elements var queuedImports = new Array(); @@ -2564,6 +2566,7 @@ export class Function extends TypedElement { tempI64s: Local[] | null = null; tempF32s: Local[] | null = null; tempF64s: Local[] | null = null; + tempV128s: Local[] | null = null; // used by flows to keep track of break labels nextBreakId: i32 = 0; diff --git a/src/resolver.ts b/src/resolver.ts index c61e402f..43f8ba37 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -74,7 +74,8 @@ import { } from "./common"; import { - makeMap + makeMap, + isPowerOf2 } from "./util"; import { @@ -1572,13 +1573,9 @@ export class Resolver extends DiagnosticEmitter { } if (!fieldType) break; // did report above let fieldInstance = new Field(member, instance, fieldType); - switch (fieldType.byteSize) { // align - case 1: break; - case 2: { if (memoryOffset & 1) ++memoryOffset; break; } - case 4: { if (memoryOffset & 3) memoryOffset = (memoryOffset | 3) + 1; break; } - case 8: { if (memoryOffset & 7) memoryOffset = (memoryOffset | 7) + 1; break; } - default: assert(false); - } + assert(isPowerOf2(fieldType.byteSize)); + let mask = fieldType.byteSize - 1; + if (memoryOffset & mask) memoryOffset = (memoryOffset | mask) + 1; fieldInstance.memoryOffset = memoryOffset; memoryOffset += fieldType.byteSize; instance.add(member.name, fieldInstance); // reports diff --git a/src/types.ts b/src/types.ts index e92fb911..d7edf20e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -55,6 +55,8 @@ export const enum TypeKind { F64, // vectors + + /** A 128-bit vector. */ V128, // other diff --git a/src/util/index.ts b/src/util/index.ts index da8ea583..219815d2 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -10,3 +10,8 @@ export * from "./collections"; export * from "./path"; export * from "./text"; export * from "./binary"; + +/** Tests if `x` is a power of two. */ +export function isPowerOf2(x: i32): bool { + return x != 0 && (x & (x - 1)) == 0; +} diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index f9a41ad3..ded0f6e1 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -33,8 +33,8 @@ @builtin export declare function reinterpret(value: void): T; @builtin export declare function sqrt(value: T): T; @builtin export declare function trunc(value: T): T; -@builtin export declare function load(offset: usize, constantOffset?: usize): T; -@builtin export declare function store(offset: usize, value: void, constantOffset?: usize): void; +@builtin export declare function load(offset: usize, immOffset?: usize, immAlign?: usize): T; +@builtin export declare function store(offset: usize, value: void, immOffset?: usize, immAlign?: usize): void; @builtin export declare function sizeof(): usize; // | u32 / u64 @builtin export declare function alignof(): usize; // | u32 / u64 @builtin export declare function offsetof(fieldName?: string): usize; // | u32 / u64 @@ -47,15 +47,15 @@ @builtin export declare function instantiate(...args: void[]): T; export namespace atomic { - @builtin export declare function load(offset: usize, constantOffset?: usize): T; - @builtin export declare function store(offset: usize, value: void, constantOffset?: usize): void; - @builtin export declare function add(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function sub(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function and(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function or(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function xor(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function xchg(ptr: usize, value: T, constantOffset?: usize): T; - @builtin export declare function cmpxchg(ptr: usize, expected:T, replacement: T, constantOffset?: usize): T; + @builtin export declare function load(offset: usize, immOffset?: usize): T; + @builtin export declare function store(offset: usize, value: void, immOffset?: usize): void; + @builtin export declare function add(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function sub(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function and(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function or(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function xor(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function xchg(ptr: usize, value: T, immOffset?: usize): T; + @builtin export declare function cmpxchg(ptr: usize, expected:T, replacement: T, immOffset?: usize): T; @builtin export declare function wait(ptr: usize, expected:T, timeout:i64): i32; @builtin export declare function notify(ptr: usize, count: u32): u32; } @@ -82,55 +82,55 @@ export namespace i32 { @builtin export declare function rotl(value: i32, shift: i32): i32; @builtin export declare function rotr(value: i32, shift: i32): i32; @builtin export declare function reinterpret_f32(value: f32): i32; - @builtin export declare function load8_s(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load8_u(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load16_s(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load16_u(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load(offset: usize, constantOffset?: usize): i32; - @builtin export declare function store8(offset: usize, value: i32, constantOffset?: usize): void; - @builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void; - @builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void; + @builtin export declare function load8_s(offset: usize, immOffset?: usize, immAlign?: usize): i32; + @builtin export declare function load8_u(offset: usize, immOffset?: usize, immAlign?: usize): i32; + @builtin export declare function load16_s(offset: usize, immOffset?: usize, immAlign?: usize): i32; + @builtin export declare function load16_u(offset: usize, immOffset?: usize, immAlign?: usize): i32; + @builtin export declare function load(offset: usize, immOffset?: usize, immAlign?: usize): i32; + @builtin export declare function store8(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function store16(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function store(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; export namespace atomic { - @builtin export declare function load8_s(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load8_u(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load16_s(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load16_u(offset: usize, constantOffset?: usize): i32; - @builtin export declare function load(offset: usize, constantOffset?: usize): i32; - @builtin export declare function store8(offset: usize, value: i32, constantOffset?: usize): void; - @builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void; - @builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void; + @builtin export declare function load8_s(offset: usize, immOffset?: usize): i32; + @builtin export declare function load8_u(offset: usize, immOffset?: usize): i32; + @builtin export declare function load16_s(offset: usize, immOffset?: usize): i32; + @builtin export declare function load16_u(offset: usize, immOffset?: usize): i32; + @builtin export declare function load(offset: usize, immOffset?: usize): i32; + @builtin export declare function store8(offset: usize, value: i32, immOffset?: usize): void; + @builtin export declare function store16(offset: usize, value: i32, immOffset?: usize): void; + @builtin export declare function store(offset: usize, value: i32, immOffset?: usize): void; @builtin export declare function wait(ptr: usize, expected:i32, timeout:i64): i32; @builtin export declare function notify(ptr: usize, count:u32): u32; export namespace rmw8_u { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; + @builtin export declare function add(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, immOffset?: usize): i32; } export namespace rmw16_u { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; + @builtin export declare function add(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, immOffset?: usize): i32; } export namespace rmw { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; - @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; + @builtin export declare function add(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, immOffset?: usize): i32; + @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, immOffset?: usize): i32; } } } @@ -141,72 +141,72 @@ export namespace i64 { @lazy export const MAX_VALUE: i64 = 9223372036854775807; @builtin export declare function clz(value: i64): i64; @builtin export declare function ctz(value: i64): i64; - @builtin export declare function load8_s(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load8_u(offset: usize, constantOffset?: usize): u64; - @builtin export declare function load16_s(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load16_u(offset: usize, constantOffset?: usize): u64; - @builtin export declare function load32_s(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load32_u(offset: usize, constantOffset?: usize): u64; - @builtin export declare function load(offset: usize, constantOffset?: usize): i64; + @builtin export declare function load8_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; + @builtin export declare function load8_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; + @builtin export declare function load16_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; + @builtin export declare function load16_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; + @builtin export declare function load32_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; + @builtin export declare function load32_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; + @builtin export declare function load(offset: usize, immOffset?: usize): i64; @builtin export declare function popcnt(value: i64): i64; @builtin export declare function rotl(value: i64, shift: i64): i64; @builtin export declare function rotr(value: i64, shift: i64): i64; @builtin export declare function reinterpret_f64(value: f64): i64; - @builtin export declare function store8(offset: usize, value: i64, constantOffset?: usize): void; - @builtin export declare function store16(offset: usize, value: i64, constantOffset?: usize): void; - @builtin export declare function store32(offset: usize, value: i64, constantOffset?: usize): void; - @builtin export declare function store(offset: usize, value: i64, constantOffset?: usize): void; + @builtin export declare function store8(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function store16(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function store32(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function store(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; namespace atomic { - @builtin export declare function load8_s(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load8_u(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load16_s(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load16_u(offset: usize, constantOffset?: usize): i64; - @builtin export declare function load(offset: usize, constantOffset?: usize): i64; - @builtin export declare function store8(offset: usize, value: i64, constantOffset?: usize): void; - @builtin export declare function store16(offset: usize, value: i64, constantOffset?: usize): void; - @builtin export declare function store(offset: usize, value: i64, constantOffset?: usize): void; + @builtin export declare function load8_s(offset: usize, immOffset?: usize): i64; + @builtin export declare function load8_u(offset: usize, immOffset?: usize): i64; + @builtin export declare function load16_s(offset: usize, immOffset?: usize): i64; + @builtin export declare function load16_u(offset: usize, immOffset?: usize): i64; + @builtin export declare function load(offset: usize, immOffset?: usize): i64; + @builtin export declare function store8(offset: usize, value: i64, immOffset?: usize): void; + @builtin export declare function store16(offset: usize, value: i64, immOffset?: usize): void; + @builtin export declare function store(offset: usize, value: i64, immOffset?: usize): void; @builtin export declare function wait(ptr: usize, expected:i64, timeout:i64): i32; @builtin export declare function notify(ptr: usize, count:u32): u32; export namespace rmw8_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; + @builtin export declare function add(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, immOffset?: usize): i64; } export namespace rmw16_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; + @builtin export declare function add(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, immOffset?: usize): i64; } export namespace rmw32_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; + @builtin export declare function add(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, immOffset?: usize): i64; } export namespace rmw { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; - @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; + @builtin export declare function add(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, immOffset?: usize): i64; + @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, immOffset?: usize): i64; } } } @@ -271,13 +271,13 @@ export namespace f32 { @builtin export declare function ceil(value: f32): f32; @builtin export declare function copysign(x: f32, y: f32): f32; @builtin export declare function floor(value: f32): f32; - @builtin export declare function load(offset: usize, constantOffset?: usize): f32; + @builtin export declare function load(offset: usize, immOffset?: usize, immAlign?: usize): f32; @builtin export declare function max(left: f32, right: f32): f32; @builtin export declare function min(left: f32, right: f32): f32; @builtin export declare function nearest(value: f32): f32; @builtin export declare function reinterpret_i32(value: i32): f32; @builtin export declare function sqrt(value: f32): f32; - @builtin export declare function store(offset: usize, value: f32, constantOffset?: usize): void; + @builtin export declare function store(offset: usize, value: f32, immOffset?: usize, immAlign?: usize): void; @builtin export declare function trunc(value: f32): f32; } @@ -293,14 +293,212 @@ export namespace f64 { @builtin export declare function ceil(value: f64): f64; @builtin export declare function copysign(x: f64, y: f64): f64; @builtin export declare function floor(value: f64): f64; - @builtin export declare function load(offset: usize, constantOffset?: usize): f64; + @builtin export declare function load(offset: usize, immOffset?: usize, immAlign?: usize): f64; @builtin export declare function max(left: f64, right: f64): f64; @builtin export declare function min(left: f64, right: f64): f64; @builtin export declare function nearest(value: f64): f64; @builtin export declare function reinterpret_i64(value: i64): f64; @builtin export declare function sqrt(value: f64): f64; - @builtin export declare function store(offset: usize, value: f64, constantOffset?: usize): void; + @builtin export declare function store(offset: usize, value: f64, immOffset?: usize, immAlign?: usize): void; @builtin export declare function trunc(value: f64): f64; } +@builtin export declare function v128(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; +export namespace v128 { + @builtin export declare function splat(x: T): v128; + @builtin export declare function extract_lane(x: v128, idx: u8): T; + @builtin export declare function replace_lane(x: v128, idx: u8, value: T): v128; + @builtin export declare function shuffle(a: v128, b: v128, ...lanes: u8[]): v128; + @builtin export declare function load(offset: usize, immOffset?: usize, immAlign?: usize): v128; + @builtin export declare function store(offset: usize, value: v128, immOffset?: usize, immAlign?: usize): void; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; // except i64 + @builtin export declare function div(a: v128, b: v128): v128; // f32, f64 only + @builtin export declare function neg(a: v128): v128; + @builtin export declare function add_saturate(a: v128, b: v128): v128; + @builtin export declare function sub_saturate(a: v128, b: v128): v128; + @builtin export declare function shl(a: v128, b: i32): v128; + @builtin export declare function shr(a: v128, b: i32): v128; + @builtin export declare function and(a: v128, b: v128): v128; + @builtin export declare function or(a: v128, b: v128): v128; + @builtin export declare function xor(a: v128, b: v128): v128; + @builtin export declare function not(a: v128): v128; + @builtin export declare function bitselect(v1: v128, v2: v128, c: v128): v128; + @builtin export declare function any_true(a: v128): bool; + @builtin export declare function all_true(a: v128): bool; + @builtin export declare function min(a: v128, b: v128): v128; // f32, f64 only + @builtin export declare function max(a: v128, b: v128): v128; // f32, f64 only + @builtin export declare function abs(a: v128): v128; // f32, f64 only + @builtin export declare function sqrt(a: v128): v128; // f32, f64 only + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt(a: v128, b: v128): v128; + @builtin export declare function le(a: v128, b: v128): v128; + @builtin export declare function gt(a: v128, b: v128): v128; + @builtin export declare function ge(a: v128, b: v128): v128; + @builtin export declare function convert(a: v128): v128; + @builtin export declare function trunc(a: v128): v128; +} + +@builtin export declare function i8x16(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; +export namespace i8x16 { + @builtin export declare function splat(x: i8): v128; + @builtin export declare function extract_lane_s(x: v128, idx: u8): i8; + @builtin export declare function extract_lane_u(x: v128, idx: u8): u8; + @builtin export declare function replace_lane(x: v128, idx: u8, value: i8): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function add_saturate_s(a: v128, b: v128): v128; + @builtin export declare function add_saturate_u(a: v128, b: v128): v128; + @builtin export declare function sub_saturate_s(a: v128, b: v128): v128; + @builtin export declare function sub_saturate_u(a: v128, b: v128): v128; + @builtin export declare function shl(a: v128, b: i32): v128; + @builtin export declare function shr_s(a: v128, b: i32): v128; + @builtin export declare function shr_u(a: v128, b: i32): v128; + @builtin export declare function any_true(a: v128): bool; + @builtin export declare function all_true(a: v128): bool; + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt_s(a: v128, b: v128): v128; + @builtin export declare function lt_u(a: v128, b: v128): v128; + @builtin export declare function le_s(a: v128, b: v128): v128; + @builtin export declare function le_u(a: v128, b: v128): v128; + @builtin export declare function gt_s(a: v128, b: v128): v128; + @builtin export declare function gt_u(a: v128, b: v128): v128; + @builtin export declare function ge_s(a: v128, b: v128): v128; + @builtin export declare function ge_u(a: v128, b: v128): v128; +} + +@builtin export declare function i16x8(a: i16, b: i16, c: i16, d: i16, e: i16, f: i16, g: i16, h: i16): v128; +export namespace i16x8 { + @builtin export declare function splat(x: i16): v128; + @builtin export declare function extract_lane_s(x: v128, idx: u8): i16; + @builtin export declare function extract_lane_u(x: v128, idx: u8): u16; + @builtin export declare function replace_lane(x: v128, idx: u8, value: i16): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function add_saturate_s(a: v128, b: v128): v128; + @builtin export declare function add_saturate_u(a: v128, b: v128): v128; + @builtin export declare function sub_saturate_s(a: v128, b: v128): v128; + @builtin export declare function sub_saturate_u(a: v128, b: v128): v128; + @builtin export declare function shl(a: v128, b: i32): v128; + @builtin export declare function shr_s(a: v128, b: i32): v128; + @builtin export declare function shr_u(a: v128, b: i32): v128; + @builtin export declare function any_true(a: v128): bool; + @builtin export declare function all_true(a: v128): bool; + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt_s(a: v128, b: v128): v128; + @builtin export declare function lt_u(a: v128, b: v128): v128; + @builtin export declare function le_s(a: v128, b: v128): v128; + @builtin export declare function le_u(a: v128, b: v128): v128; + @builtin export declare function gt_s(a: v128, b: v128): v128; + @builtin export declare function gt_u(a: v128, b: v128): v128; + @builtin export declare function ge_s(a: v128, b: v128): v128; + @builtin export declare function ge_u(a: v128, b: v128): v128; +} + +@builtin export declare function i32x4(a: i32, b: i32, c: i32, d: i32): v128; +export namespace i32x4 { + @builtin export declare function splat(x: i32): v128; + @builtin export declare function extract_lane(x: v128, idx: u8): i32; + @builtin export declare function replace_lane(x: v128, idx: u8, value: i32): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function shl(a: v128, b: i32): v128; + @builtin export declare function shr_s(a: v128, b: i32): v128; + @builtin export declare function shr_u(a: v128, b: i32): v128; + @builtin export declare function any_true(a: v128): bool; + @builtin export declare function all_true(a: v128): bool; + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt_s(a: v128, b: v128): v128; + @builtin export declare function lt_u(a: v128, b: v128): v128; + @builtin export declare function le_s(a: v128, b: v128): v128; + @builtin export declare function le_u(a: v128, b: v128): v128; + @builtin export declare function gt_s(a: v128, b: v128): v128; + @builtin export declare function gt_u(a: v128, b: v128): v128; + @builtin export declare function ge_s(a: v128, b: v128): v128; + @builtin export declare function ge_u(a: v128, b: v128): v128; + @builtin export declare function trunc_s_f32x4_sat(a: v128): v128; + @builtin export declare function trunc_u_f32x4_sat(a: v128): v128; +} + +@builtin export declare function i64x2(a: i64, b: i64): v128; +export namespace i64x2 { + @builtin export declare function splat(x: i64): v128; + @builtin export declare function extract_lane(x: v128, idx: u8): i64; + @builtin export declare function replace_lane(x: v128, idx: u8, value: i64): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function shl(a: v128, b: i32): v128; + @builtin export declare function shr_s(a: v128, b: i32): v128; + @builtin export declare function shr_u(a: v128, b: i32): v128; + @builtin export declare function any_true(a: v128): bool; + @builtin export declare function all_true(a: v128): bool; + @builtin export declare function trunc_s_f64x2_sat(a: v128): v128; + @builtin export declare function trunc_u_f64x2_sat(a: v128): v128; +} + +@builtin export declare function f32x4(a: f32, b: f32, c: f32, d: f32): v128; +export namespace f32x4 { + @builtin export declare function splat(x: f32): v128; + @builtin export declare function extract_lane(x: v128, idx: u8): f32; + @builtin export declare function replace_lane(x: v128, idx: u8, value: f32): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function div(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function min(a: v128, b: v128): v128; + @builtin export declare function max(a: v128, b: v128): v128; + @builtin export declare function abs(a: v128): v128; + @builtin export declare function sqrt(a: v128): v128; + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt(a: v128, b: v128): v128; + @builtin export declare function le(a: v128, b: v128): v128; + @builtin export declare function gt(a: v128, b: v128): v128; + @builtin export declare function ge(a: v128, b: v128): v128; + @builtin export declare function convert_s_i32x4(a: v128): v128; + @builtin export declare function convert_u_i32x4(a: v128): v128; +} + +@builtin export declare function f64x2(a: f64, b: f64): v128; +export namespace f64x2 { + @builtin export declare function splat(x: f64): v128; + @builtin export declare function extract_lane(x: v128, idx: u8): f64; + @builtin export declare function replace_lane(x: v128, idx: u8, value: f64): v128; + @builtin export declare function add(a: v128, b: v128): v128; + @builtin export declare function sub(a: v128, b: v128): v128; + @builtin export declare function mul(a: v128, b: v128): v128; + @builtin export declare function div(a: v128, b: v128): v128; + @builtin export declare function neg(a: v128): v128; + @builtin export declare function min(a: v128, b: v128): v128; + @builtin export declare function max(a: v128, b: v128): v128; + @builtin export declare function abs(a: v128): v128; + @builtin export declare function sqrt(a: v128): v128; + @builtin export declare function eq(a: v128, b: v128): v128; + @builtin export declare function ne(a: v128, b: v128): v128; + @builtin export declare function lt(a: v128, b: v128): v128; + @builtin export declare function le(a: v128, b: v128): v128; + @builtin export declare function gt(a: v128, b: v128): v128; + @builtin export declare function ge(a: v128, b: v128): v128; + @builtin export declare function convert_s_i64x2(a: v128): v128; + @builtin export declare function convert_u_i64x2(a: v128): v128; +} + +export namespace v8x16 { + @builtin export declare function shuffle(a: v128, b: v128, l0: u8, l1: u8, l2: u8, l3: u8, l4: u8, l5: u8, l6: u8, l7: u8, l8: u8, l9: u8, l10: u8, l11: u8, l12: u8, l13: u8, l14: u8, l15: u8): v128; +} + @builtin export declare function start(): void; diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 021af3f5..5ece5659 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -33,6 +33,8 @@ declare type bool = boolean | number; declare type f32 = number; /** A 64-bit float. */ declare type f64 = number; +/** A 128-bit vector. */ +declare type v128 = object; // Compiler hints @@ -50,6 +52,12 @@ declare const ASC_SHRINK_LEVEL: i32; declare const ASC_FEATURE_MUTABLE_GLOBAL: bool; /** Whether the sign extension feature is enabled. */ declare const ASC_FEATURE_SIGN_EXTENSION: bool; +/** Whether the bulk memory feature is enabled. */ +declare const ASC_FEATURE_BULK_MEMORY: bool; +/** Whether the SIMD feature is enabled. */ +declare const ASC_FEATURE_SIMD: bool; +/** Whether the threads feature is enabled. */ +declare const ASC_FEATURE_THREADS: bool; // Builtins @@ -86,9 +94,9 @@ declare function sqrt(value: T): T; /** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */ declare function trunc(value: T): T; /** Loads a value of the specified type from memory. Equivalent to dereferncing a pointer in other languages. */ -declare function load(ptr: usize, constantOffset?: usize): T; +declare function load(ptr: usize, immOffset?: usize, immAlign?: usize): T; /** Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value. */ -declare function store(ptr: usize, value: any, constantOffset?: usize): void; +declare function store(ptr: usize, value: any, immOffset?: usize, immAlign?: usize): void; /** Emits an unreachable operation that results in a runtime error when executed. Both a statement and an expression of any type. */ declare function unreachable(): any; // sic @@ -162,10 +170,6 @@ declare namespace i8 { export const MIN_VALUE: i8; /** Largest representable value. */ export const MAX_VALUE: i8; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): i8; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): i8; } /** Converts any other numeric value to a 16-bit signed integer. */ declare function i16(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; @@ -174,10 +178,6 @@ declare namespace i16 { export const MIN_VALUE: i16; /** Largest representable value. */ export const MAX_VALUE: i16; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): i16; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): i16; } /** Converts any other numeric value to a 32-bit signed integer. */ declare function i32(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i32; @@ -187,25 +187,21 @@ declare namespace i32 { /** Largest representable value. */ export const MAX_VALUE: i32; /** Loads an 8-bit signed integer from memory and returns it as a 32-bit integer. */ - export function load8_s(offset: usize, constantOffset?: usize): i32; + export function load8_s(offset: usize, immOffset?: usize, immAlign?: usize): i32; /** Loads an 8-bit unsigned integer from memory and returns it as a 32-bit integer. */ - export function load8_u(offset: usize, constantOffset?: usize): i32; + export function load8_u(offset: usize, immOffset?: usize, immAlign?: usize): i32; /** Loads a 16-bit signed integer from memory and returns it as a 32-bit integer. */ - export function load16_s(offset: usize, constantOffset?: usize): i32; + export function load16_s(offset: usize, immOffset?: usize, immAlign?: usize): i32; /** Loads a 16-bit unsigned integer from memory and returns it as a 32-bit integer. */ - export function load16_u(offset: usize, constantOffset?: usize): i32; + export function load16_u(offset: usize, immOffset?: usize, immAlign?: usize): i32; /** Loads a 32-bit integer from memory. */ - export function load(offset: usize, constantOffset?: usize): i32; + export function load(offset: usize, immOffset?: usize, immAlign?: usize): i32; /** Stores a 32-bit integer to memory as an 8-bit integer. */ - export function store8(offset: usize, value: i32, constantOffset?: usize): void; + export function store8(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; /** Stores a 32-bit integer to memory as a 16-bit integer. */ - export function store16(offset: usize, value: i32, constantOffset?: usize): void; + export function store16(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; /** Stores a 32-bit integer to memory. */ - export function store(offset: usize, value: i32, constantOffset?: usize): void; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): i32; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): i32; + export function store(offset: usize, value: i32, immOffset?: usize, immAlign?: usize): void; } /** Converts any other numeric value to a 64-bit signed integer. */ declare function i64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i64; @@ -215,31 +211,27 @@ declare namespace i64 { /** Largest representable value. */ export const MAX_VALUE: i64; /** Loads an 8-bit signed integer from memory and returns it as a 64-bit signed integer. */ - export function load8_s(offset: usize, constantOffset?: usize): i64; + export function load8_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; /** Loads an 8-bit unsigned integer from memory and returns it as a 64-bit unsigned integer. */ - export function load8_u(offset: usize, constantOffset?: usize): u64; + export function load8_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; /** Loads a 16-bit signed integer from memory and returns it as a 64-bit signed integer. */ - export function load16_s(offset: usize, constantOffset?: usize): i64; + export function load16_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; /** Loads a 16-bit unsigned integer from memory and returns it as a 64-bit unsigned integer. */ - export function load16_u(offset: usize, constantOffset?: usize): u64; + export function load16_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; /** Loads a 32-bit signed integer from memory and returns it as a 64-bit signed integer. */ - export function load32_s(offset: usize, constantOffset?: usize): i64; + export function load32_s(offset: usize, immOffset?: usize, immAlign?: usize): i64; /** Loads a 32-bit unsigned integer from memory and returns it as a 64-bit unsigned integer. */ - export function load32_u(offset: usize, constantOffset?: usize): u64; + export function load32_u(offset: usize, immOffset?: usize, immAlign?: usize): u64; /** Loads a 64-bit unsigned integer from memory. */ - export function load(offset: usize, constantOffset?: usize): i64; + export function load(offset: usize, immOffset?: usize, immAlign?: usize): i64; /** Stores a 64-bit integer to memory as an 8-bit integer. */ - export function store8(offset: usize, value: i64, constantOffset?: usize): void; + export function store8(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; /** Stores a 64-bit integer to memory as a 16-bit integer. */ - export function store16(offset: usize, value: i64, constantOffset?: usize): void; + export function store16(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; /** Stores a 64-bit integer to memory as a 32-bit integer. */ - export function store32(offset: usize, value: i64, constantOffset?: usize): void; + export function store32(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; /** Stores a 64-bit integer to memory. */ - export function store(offset: usize, value: i64, constantOffset?: usize): void; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): i64; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): i64; + export function store(offset: usize, value: i64, immOffset?: usize, immAlign?: usize): void; } /** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) signed integer. */ declare var isize: typeof i32 | typeof i64; @@ -250,10 +242,6 @@ declare namespace u8 { export const MIN_VALUE: u8; /** Largest representable value. */ export const MAX_VALUE: u8; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): u8; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): u8; } /** Converts any other numeric value to a 16-bit unsigned integer. */ declare function u16(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8; @@ -262,10 +250,6 @@ declare namespace u16 { export const MIN_VALUE: u16; /** Largest representable value. */ export const MAX_VALUE: u16; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): u16; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): u16; } /** Converts any other numeric value to a 32-bit unsigned integer. */ declare function u32(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i32; @@ -274,10 +258,6 @@ declare namespace u32 { export const MIN_VALUE: u32; /** Largest representable value. */ export const MAX_VALUE: u32; - /** Converts a string to a floating-point number and cast to target integer after. */ - export function parseFloat(string: string): u64; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): u64; } /** Converts any other numeric value to a 64-bit unsigned integer. */ declare function u64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i64; @@ -286,10 +266,6 @@ declare namespace u64 { export const MIN_VALUE: u64; /** Largest representable value. */ export const MAX_VALUE: u64; - /** Converts a string to a floating-point number. */ - export function parseFloat(string: string): u64; - /** Converts A string to an integer. */ - export function parseInt(string: string, radix?: i32): u64; } /** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) unsigned integer. */ declare var usize: typeof u32 | typeof u64; @@ -316,26 +292,10 @@ declare namespace f32 { export const MAX_SAFE_INTEGER: f32; /** Difference between 1 and the smallest representable value greater than 1. */ export const EPSILON: f32; - /** Returns the floating-point remainder of `x / y` (rounded towards zero). */ - export function mod(x: f32, y: f32): f32; - /** Returns the floating-point remainder of `x / y` (rounded to nearest). */ - export function rem(x: f32, y: f32): f32; /** Loads a 32-bit float from memory. */ - export function load(offset: usize, constantOffset?: usize): f32; + export function load(offset: usize, immOffset?: usize, immAlign?: usize): f32; /** Stores a 32-bit float to memory. */ - export function store(offset: usize, value: f32, constantOffset?: usize): void; - /** Returns a boolean value that indicates whether a value is the reserved value NaN (not a number). */ - export function isNaN(value: f32): bool; - /** Returns true if passed value is finite. */ - export function isFinite(value: f32): bool; - /** Returns true if the value passed is a safe integer. */ - export function isSafeInteger(value: f32): bool; - /** Returns true if the value passed is an integer, false otherwise. */ - export function isInteger(value: f32): bool; - /** Converts a string to a floating-point number. */ - export function parseFloat(string: string): f32; - /** Converts a string to an integer. */ - export function parseInt(string: string, radix?: i32): f32; + export function store(offset: usize, value: f32, immOffset?: usize, immAlign?: usize): void; } /** Converts any other numeric value to a 64-bit float. */ declare function f64(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): f64; @@ -353,9 +313,373 @@ declare namespace f64 { /** Difference between 1 and the smallest representable value greater than 1. */ export const EPSILON: f64; /** Loads a 64-bit float from memory. */ - export function load(offset: usize, constantOffset?: usize): f64; + export function load(offset: usize, immOffset?: usize, immAlign?: usize): f64; /** Stores a 64-bit float to memory. */ - export function store(offset: usize, value: f64, constantOffset?: usize): void; + export function store(offset: usize, value: f64, immOffset?: usize, immAlign?: usize): void; +} +/** Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants. */ +declare function v128(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; +declare namespace v128 { + /** Creates a 128-bit vector with identical lanes. */ + export function splat(x: T): v128; + /** Extracts one lane from a 128-bit vector as a scalar. */ + export function extract_lane(x: v128, idx: u8): T; + /** Replaces one lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: T): v128; + /** Selects lanes from either 128-bit vector according to the specified lane indexes. */ + export function shuffle(a: v128, b: v128, ...lanes: u8[]): v128; + /** Loads a 128-bit vector from memory. */ + export function load(offset: usize, immOffset?: usize, immAlign?: usize): v128; + /** Stores a 128-bit vector to memory. */ + export function store(offset: usize, value: v128, immOffset?: usize, immAlign?: usize): void; + /** Adds each lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; // except i64 + /** Divides each lane of two 128-bit vectors. */ + export function div(a: v128, b: v128): v128; + /** Negates each lane of a 128-bit vector */ + export function neg(a: v128): v128; + /** Adds each lane of two 128-bit vectors using saturation. */ + export function add_saturate(a: v128, b: v128): v128; + /** Subtracts each lane of two 128-bit vectors using saturation. */ + export function sub_saturate(a: v128, b: v128): v128; + /** Performs a bitwise left shift on each lane of a 128-bit vector by a scalar. */ + export function shl(a: v128, b: i32): v128; + /** Performs a bitwise right shift on each lane of a 128-bit vector by a scalar. */ + export function shr(a: v128, b: i32): v128; + /** Performs the bitwise AND operation on each lane of two 128-bit vectors. */ + export function and(a: v128, b: v128): v128; + /** Performs the bitwise OR operation on each lane of two 128-bit vectors. */ + export function or(a: v128, b: v128): v128; + /** Performs the bitwise XOR operation on each lane of two 128-bit vectors. */ + export function xor(a: v128, b: v128): v128; + /** Performs the bitwise NOT operation on each lane of a 128-bit vector. */ + export function not(a: v128): v128; + /** Selects bits of either 128-bit vector according to the specified mask. */ + export function bitselect(v1: v128, v2: v128, mask: v128): v128; + /** Reduces a 128-bit vector to a scalar indicating whether any lane is considered `true`. */ + export function any_true(a: v128): bool; + /** Reduces a 128-bit vector to a scalar indicating whether all lanes are considered `true`. */ + export function all_true(a: v128): bool; + /** Computes the minimum of each lane of two 128-bit vectors. */ + export function min(a: v128, b: v128): v128; + /** Computes the maximum of each lane of two 128-bit vectors. */ + export function max(a: v128, b: v128): v128; + /** Computes the absolute value of each lane of a 128-bit vector. */ + export function abs(a: v128): v128; + /** Computes the square root of each lane of a 128-bit vector. */ + export function sqrt(a: v128): v128; + /** Computes which lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which lanes of the first 128-bit vector are less than those of the second. */ + export function lt(a: v128, b: v128): v128; + /** Computes which lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le(a: v128, b: v128): v128; + /** Computes which lanes of the first 128-bit vector are greater than those of the second. */ + export function gt(a: v128, b: v128): v128; + /** Computes which lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge(a: v128, b: v128): v128; + /** Converts each lane of a 128-bit vector from integer to floating point. */ + export function convert(a: v128): v128; + /** Truncates each lane of a 128-bit vector from floating point to integer with saturation. */ + export function trunc(a: v128): v128; +} +/** Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants. */ +declare function i8x16(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; +declare namespace i8x16 { + /** Creates a vector with sixteen identical 8-bit integer lanes. */ + export function splat(x: i8): v128; + /** Extracts one 8-bit integer lane from a 128-bit vector as a signed scalar. */ + export function extract_lane_s(x: v128, idx: u8): i8; + /** Extracts one 8-bit integer lane from a 128-bit vector as an unsigned scalar. */ + export function extract_lane_u(x: v128, idx: u8): u8; + /** Replaces one 8-bit integer lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: i8): v128; + /** Adds each 8-bit integer lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 8-bit integer lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 8-bit integer lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Negates each 8-bit integer lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Adds each 8-bit integer lane of two 128-bit vectors using signed saturation. */ + export function add_saturate_s(a: v128, b: v128): v128; + /** Adds each 8-bit integer lane of two 128-bit vectors using unsigned saturation. */ + export function add_saturate_u(a: v128, b: v128): v128; + /** Subtracts each 8-bit integer lane of two 128-bit vectors using signed saturation. */ + export function sub_saturate_s(a: v128, b: v128): v128; + /** Subtracts each 8-bit integer lane of two 128-bit vectors using unsigned saturation. */ + export function sub_saturate_u(a: v128, b: v128): v128; + /** Performs a bitwise left shift on each 8-bit integer lane of a 128-bit vector by a scalar. */ + export function shl(a: v128, b: i32): v128; + /** Performs a bitwise arithmetic right shift on each 8-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_s(a: v128, b: i32): v128; + /** Performs a bitwise logical right shift on each 8-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_u(a: v128, b: i32): v128; + /** Reduces a 128-bit vector to a scalar indicating whether any 8-bit integer lane is considered `true`. */ + export function any_true(a: v128): bool; + /** Reduces a 128-bit vector to a scalar indicating whether all 8-bit integer lanes are considered `true`. */ + export function all_true(a: v128): bool; + /** Computes which 8-bit integer lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which 8-bit integer lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which 8-bit signed integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_s(a: v128, b: v128): v128; + /** Computes which 8-bit unsigned integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_u(a: v128, b: v128): v128; + /** Computes which 8-bit signed integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_s(a: v128, b: v128): v128; + /** Computes which 8-bit unsigned integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_u(a: v128, b: v128): v128; + /** Computes which 8-bit signed integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_s(a: v128, b: v128): v128; + /** Computes which 8-bit unsigned integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_u(a: v128, b: v128): v128; + /** Computes which 8-bit signed integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_s(a: v128, b: v128): v128; + /** Computes which 8-bit unsigned integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_u(a: v128, b: v128): v128; +} +/** Initializes a 128-bit vector from eight 16-bit integer values. Arguments must be compile-time constants. */ +declare function i16x8(a: i16, b: i16, c: i16, d: i16, e: i16, f: i16, g: i16, h: i16): v128; +declare namespace i16x8 { + /** Creates a vector with eight identical 16-bit integer lanes. */ + export function splat(x: i16): v128; + /** Extracts one 16-bit integer lane from a 128-bit vector as a signed scalar. */ + export function extract_lane_s(x: v128, idx: u8): i16; + /** Extracts one 16-bit integer lane from a 128-bit vector as an unsigned scalar. */ + export function extract_lane_u(x: v128, idx: u8): u16; + /** Replaces one 16-bit integer lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: i16): v128; + /** Adds each 16-bit integer lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 16-bit integer lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 16-bit integer lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Negates each 16-bit integer lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Adds each 16-bit integer lane of two 128-bit vectors using signed saturation. */ + export function add_saturate_s(a: v128, b: v128): v128; + /** Adds each 16-bit integer lane of two 128-bit vectors using unsigned saturation. */ + export function add_saturate_u(a: v128, b: v128): v128; + /** Subtracts each 16-bit integer lane of two 128-bit vectors using signed saturation. */ + export function sub_saturate_s(a: v128, b: v128): v128; + /** Subtracts each 16-bit integer lane of two 128-bit vectors using unsigned saturation. */ + export function sub_saturate_u(a: v128, b: v128): v128; + /** Performs a bitwise left shift on each 16-bit integer lane of a 128-bit vector by a scalar. */ + export function shl(a: v128, b: i32): v128; + /** Performs a bitwise arithmetic right shift each 16-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_s(a: v128, b: i32): v128; + /** Performs a bitwise logical right shift on each 16-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_u(a: v128, b: i32): v128; + /** Reduces a 128-bit vector to a scalar indicating whether any 16-bit integer lane is considered `true`. */ + export function any_true(a: v128): bool; + /** Reduces a 128-bit vector to a scalar indicating whether all 16-bit integer lanes are considered `true`. */ + export function all_true(a: v128): bool; + /** Computes which 16-bit integer lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which 16-bit integer lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which 16-bit signed integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_s(a: v128, b: v128): v128; + /** Computes which 16-bit unsigned integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_u(a: v128, b: v128): v128; + /** Computes which 16-bit signed integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_s(a: v128, b: v128): v128; + /** Computes which 16-bit unsigned integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_u(a: v128, b: v128): v128; + /** Computes which 16-bit signed integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_s(a: v128, b: v128): v128; + /** Computes which 16-bit unsigned integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_u(a: v128, b: v128): v128; + /** Computes which 16-bit signed integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_s(a: v128, b: v128): v128; + /** Computes which 16-bit unsigned integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_u(a: v128, b: v128): v128; +} +/** Initializes a 128-bit vector from four 32-bit integer values. Arguments must be compile-time constants. */ +declare function i32x4(a: i32, b: i32, c: i32, d: i32): v128; +declare namespace i32x4 { + /** Creates a 128-bit vector with four identical 32-bit integer lanes. */ + export function splat(x: i32): v128; + /** Extracts one 32-bit integer lane from a 128-bit vector as a scalar. */ + export function extract_lane(x: v128, idx: u8): i32; + /** Replaces one 32-bit integer lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: i32): v128; + /** Adds each 32-bit integer lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 32-bit integer lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 32-bit integer lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Negates each 32-bit integer lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Performs a bitwise left shift on each 32-bit integer lane of a 128-bit vector by a scalar. */ + export function shl(a: v128, b: i32): v128; + /** Performs a bitwise arithmetic right shift on each 32-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_s(a: v128, b: i32): v128; + /** Performs a bitwise logical right shift on each 32-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_u(a: v128, b: i32): v128; + /** Reduces a 128-bit vector to a scalar indicating whether any 32-bit integer lane is considered `true`. */ + export function any_true(a: v128): bool; + /** Reduces a 128-bit vector to a scalar indicating whether all 32-bit integer lanes are considered `true`. */ + export function all_true(a: v128): bool; + /** Computes which 32-bit integer lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which 32-bit integer lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which 32-bit signed integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_s(a: v128, b: v128): v128; + /** Computes which 32-bit unsigned integer lanes of the first 128-bit vector are less than those of the second. */ + export function lt_u(a: v128, b: v128): v128; + /** Computes which 32-bit signed integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_s(a: v128, b: v128): v128; + /** Computes which 32-bit unsigned integer lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le_u(a: v128, b: v128): v128; + /** Computes which 32-bit signed integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_s(a: v128, b: v128): v128; + /** Computes which 32-bit unsigned integer lanes of the first 128-bit vector are greater than those of the second. */ + export function gt_u(a: v128, b: v128): v128; + /** Computes which 32-bit signed integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_s(a: v128, b: v128): v128; + /** Computes which 32-bit unsigned integer lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge_u(a: v128, b: v128): v128; + /** Truncates each 32-bit float lane of a 128-bit vector to a signed integer with saturation. */ + export function trunc_s_f32x4_sat(a: v128): v128; + /** Truncates each 32-bit float lane of a 128-bit vector to an unsigned integer with saturation. */ + export function trunc_u_f32x4_sat(a: v128): v128; +} +/** Initializes a 128-bit vector from two 64-bit integer values. Arguments must be compile-time constants. */ +declare function i64x2(a: i64, b: i64): v128; +declare namespace i64x2 { + /** Creates a 128-bit vector with two identical 64-bit integer lanes. */ + export function splat(x: i64): v128; + /** Extracts one 64-bit integer lane from a 128-bit vector as a scalar. */ + export function extract_lane(x: v128, idx: u8): i64; + /** Replaces one 64-bit integer lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: i64): v128; + /** Adds each 64-bit integer lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 64-bit integer lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 64-bit integer lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Negates each 64-bit integer lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Performs a bitwise left shift on each 64-bit integer lane of a 128-bit vector by a scalar. */ + export function shl(a: v128, b: i32): v128; + /** Performs a bitwise arithmetic right shift on each 64-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_s(a: v128, b: i32): v128; + /** Performs a bitwise logical right shift on each 64-bit integer lane of a 128-bit vector by a scalar. */ + export function shr_u(a: v128, b: i32): v128; + /** Reduces a 128-bit vector to a scalar indicating whether any 64-bit integer lane is considered `true`. */ + export function any_true(a: v128): bool; + /** Reduces a 128-bit vector to a scalar indicating whether all 64-bit integer lanes are considered `true`. */ + export function all_true(a: v128): bool; + /** Truncates each 64-bit float lane of a 128-bit vector to a signed integer with saturation. */ + export function trunc_s_f64x2_sat(a: v128): v128; + /** Truncates each 64-bit float lane of a 128-bit vector to an unsigned integer with saturation. */ + export function trunc_u_f64x2_sat(a: v128): v128; +} +/** Initializes a 128-bit vector from four 32-bit float values. Arguments must be compile-time constants. */ +declare function f32x4(a: f32, b: f32, c: f32, d: f32): v128; +declare namespace f32x4 { + /** Creates a 128-bit vector with four identical 32-bit float lanes. */ + export function splat(x: f32): v128; + /** Extracts one 32-bit float lane from a 128-bit vector as a scalar. */ + export function extract_lane(x: v128, idx: u8): f32; + /** Replaces one 32-bit float lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: f32): v128; + /** Adds each 32-bit float lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 32-bit float lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 32-bit float lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Divides each 32-bit float lane of two 128-bit vectors. */ + export function div(a: v128, b: v128): v128; + /** Negates each 32-bit float lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Computes the minimum of each 32-bit float lane of two 128-bit vectors. */ + export function min(a: v128, b: v128): v128; + /** Computes the maximum of each 32-bit float lane of two 128-bit vectors. */ + export function max(a: v128, b: v128): v128; + /** Computes the absolute value of each 32-bit float lane of a 128-bit vector. */ + export function abs(a: v128): v128; + /** Computes the square root of each 32-bit float lane of a 128-bit vector. */ + export function sqrt(a: v128): v128; + /** Computes which 32-bit float lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which 32-bit float lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which 32-bit float lanes of the first 128-bit vector are less than those of the second. */ + export function lt(a: v128, b: v128): v128; + /** Computes which 32-bit float lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le(a: v128, b: v128): v128; + /** Computes which 32-bit float lanes of the first 128-bit vector are greater than those of the second. */ + export function gt(a: v128, b: v128): v128; + /** Computes which 32-bit float lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge(a: v128, b: v128): v128; + /** Converts each 32-bit signed integer lane of a 128-bit vector to floating point. */ + export function convert_s_i32x4(a: v128): v128; + /** Converts each 32-bit unsigned integer lane of a 128-bit vector to floating point. */ + export function convert_u_i32x4(a: v128): v128; +} +/** Initializes a 128-bit vector from two 64-bit float values. Arguments must be compile-time constants. */ +declare function f64x2(a: f64, b: f64): v128; +declare namespace f64x2 { + /** Creates a 128-bit vector with two identical 64-bit float lanes. */ + export function splat(x: f64): v128; + /** Extracts one 64-bit float lane from a 128-bit vector as a scalar. */ + export function extract_lane(x: v128, idx: u8): f64; + /** Replaces one 64-bit float lane in a 128-bit vector. */ + export function replace_lane(x: v128, idx: u8, value: f64): v128; + /** Adds each 64-bit float lane of two 128-bit vectors. */ + export function add(a: v128, b: v128): v128; + /** Subtracts each 64-bit float lane of two 128-bit vectors. */ + export function sub(a: v128, b: v128): v128; + /** Multiplies each 64-bit float lane of two 128-bit vectors. */ + export function mul(a: v128, b: v128): v128; + /** Divides each 64-bit float lane of two 128-bit vectors. */ + export function div(a: v128, b: v128): v128; + /** Negates each 64-bit float lane of a 128-bit vector. */ + export function neg(a: v128): v128; + /** Computes the minimum of each 64-bit float lane of two 128-bit vectors. */ + export function min(a: v128, b: v128): v128; + /** Computes the maximum of each 64-bit float lane of two 128-bit vectors. */ + export function max(a: v128, b: v128): v128; + /** Computes the absolute value of each 64-bit float lane of a 128-bit vector. */ + export function abs(a: v128): v128; + /** Computes the square root of each 64-bit float lane of a 128-bit vector. */ + export function sqrt(a: v128): v128; + /** Computes which 64-bit float lanes of two 128-bit vectors are equal. */ + export function eq(a: v128, b: v128): v128; + /** Computes which 64-bit float lanes of two 128-bit vectors are not equal. */ + export function ne(a: v128, b: v128): v128; + /** Computes which 64-bit float lanes of the first 128-bit vector are less than those of the second. */ + export function lt(a: v128, b: v128): v128; + /** Computes which 64-bit float lanes of the first 128-bit vector are less than or equal those of the second. */ + export function le(a: v128, b: v128): v128; + /** Computes which 64-bit float lanes of the first 128-bit vector are greater than those of the second. */ + export function gt(a: v128, b: v128): v128; + /** Computes which 64-bit float lanes of the first 128-bit vector are greater than or equal those of the second. */ + export function ge(a: v128, b: v128): v128; + /** Converts each 64-bit signed integer lane of a 128-bit vector to floating point. */ + export function convert_s_i64x2(a: v128): v128; + /** Converts each 64-bit unsigned integer lane of a 128-bit vector to floating point. */ + export function convert_u_i64x2(a: v128): v128; +} +declare namespace v8x16 { + /** Selects 8-bit lanes from either 128-bit vector according to the specified lane indexes. */ + export function shuffle(a: v128, b: v128, l0: u8, l1: u8, l2: u8, l3: u8, l4: u8, l5: u8, l6: u8, l7: u8, l8: u8, l9: u8, l10: u8, l11: u8, l12: u8, l13: u8, l14: u8, l15: u8): v128; } /** Macro type evaluating to the underlying native WebAssembly type. */ declare type native = T; @@ -398,7 +722,7 @@ declare class _Float { static isSafeInteger(value: f32 | f64): bool; /** Returns true if the value passed is an integer, false otherwise. */ static isInteger(value: f32 | f64): bool; - /** Converts A string to an integer. */ + /** Converts a string to an integer. */ static parseInt(value: string, radix?: i32): f32 | f64; /** Converts a string to a floating-point number. */ static parseFloat(value: string): f32 | f64; diff --git a/tests/compiler.js b/tests/compiler.js index a73cb346..77d6041f 100644 --- a/tests/compiler.js +++ b/tests/compiler.js @@ -1,6 +1,7 @@ const fs = require("fs"); const path = require("path"); const os = require("os"); +const v8 = require("v8"); const glob = require("glob"); const colorsUtil = require("../cli/util/colors"); const optionsUtil = require("../cli/util/options"); @@ -48,6 +49,9 @@ if (args.help) { process.exit(0); } +const features = process.env.ASC_FEATURES ? process.env.ASC_FEATURES.split(",") : []; +const featuresConfig = require("./features.json"); + var successes = 0; var failedTests = []; var failedInstantiates = new Map(); @@ -89,6 +93,40 @@ tests.forEach(filename => { const stderr = asc.createMemoryStream(chunk => process.stderr.write(chunk.toString().replace(/^(?!$)/mg, " "))); stderr.isTTY = true; + const configPath = path.join(basedir, basename + ".json"); + const config = fs.existsSync(configPath) + ? require(configPath) + : {}; + + var asc_flags = []; + var v8_flags = ""; + var v8_no_flags = ""; + var missing_features = []; + if (config.features) { + config.features.forEach(feature => { + if (!features.includes(feature)) missing_features.push(feature); + var featureConfig = featuresConfig[feature]; + if (featureConfig.asc_flags) { + featureConfig.asc_flags.forEach(flag => { + Array.prototype.push.apply(asc_flags, flag.split(" ")); + }); + } + if (featureConfig.v8_flags) { + featureConfig.v8_flags.forEach(flag => { + if (v8_flags) v8_flags += " "; + v8_flags += flag; + if (v8_no_flags) v8_no_flags += " "; + v8_no_flags += "--no-" + flag.substring(2); + }); + v8.setFlagsFromString(v8_flags); + } + }); + if (missing_features.length) { + console.log("- " + colorsUtil.yellow("feature SKIPPED") + " (" + missing_features.join(", ") + ")\n"); + return; + } + } + var failed = false; // TODO: also save stdout/stderr and diff it (-> expected failures) @@ -102,6 +140,8 @@ tests.forEach(filename => { "--debug", "--textFile" // -> stdout ]; + if (asc_flags) + Array.prototype.push.apply(cmd, asc_flags); if (args.createBinary) cmd.push("--binaryFile", basename + ".untouched.wasm"); asc.main(cmd, { @@ -167,6 +207,8 @@ tests.forEach(filename => { "--binaryFile", // -> stdout "-O3" ]; + if (asc_flags) + Array.prototype.push.apply(cmd, asc_flags); if (args.create) cmd.push("--textFile", basename + ".optimized.wat"); asc.main(cmd, { @@ -261,6 +303,7 @@ tests.forEach(filename => { console.log(); }); }); + if (v8_no_flags) v8.setFlagsFromString(v8_no_flags); }); if (failedTests.length) { diff --git a/tests/compiler/asc-constants.ts b/tests/compiler/asc-constants.ts index d940aef9..296f9ce8 100644 --- a/tests/compiler/asc-constants.ts +++ b/tests/compiler/asc-constants.ts @@ -5,3 +5,6 @@ ASC_OPTIMIZE_LEVEL; ASC_SHRINK_LEVEL; ASC_FEATURE_MUTABLE_GLOBAL; ASC_FEATURE_SIGN_EXTENSION; +ASC_FEATURE_BULK_MEMORY; +ASC_FEATURE_SIMD; +ASC_FEATURE_THREADS; diff --git a/tests/compiler/asc-constants.untouched.wat b/tests/compiler/asc-constants.untouched.wat index 0dcc88cf..f254cc54 100644 --- a/tests/compiler/asc-constants.untouched.wat +++ b/tests/compiler/asc-constants.untouched.wat @@ -10,6 +10,9 @@ (global $~lib/ASC_SHRINK_LEVEL i32 (i32.const 0)) (global $~lib/ASC_FEATURE_MUTABLE_GLOBAL i32 (i32.const 0)) (global $~lib/ASC_FEATURE_SIGN_EXTENSION i32 (i32.const 0)) + (global $~lib/ASC_FEATURE_BULK_MEMORY i32 (i32.const 0)) + (global $~lib/ASC_FEATURE_SIMD i32 (i32.const 0)) + (global $~lib/ASC_FEATURE_THREADS i32 (i32.const 0)) (global $~lib/memory/HEAP_BASE i32 (i32.const 8)) (export "memory" (memory $0)) (export "table" (table $0)) @@ -29,6 +32,12 @@ drop i32.const 0 drop + i32.const 0 + drop + i32.const 0 + drop + i32.const 0 + drop ) (func $start (; 1 ;) (type $_) call $start:asc-constants diff --git a/tests/compiler/simd.json b/tests/compiler/simd.json new file mode 100644 index 00000000..15ece5b4 --- /dev/null +++ b/tests/compiler/simd.json @@ -0,0 +1,5 @@ +{ + "features": [ + "simd" + ] +} diff --git a/tests/compiler/simd.optimized.wat b/tests/compiler/simd.optimized.wat new file mode 100644 index 00000000..60085e4e --- /dev/null +++ b/tests/compiler/simd.optimized.wat @@ -0,0 +1,21 @@ +(module + (type $_ (func)) + (memory $0 1) + (data (i32.const 8) "\07\00\00\00s\00i\00m\00d\00.\00t\00s") + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (export "table" (table $0)) + (start $start) + (func $start (; 0 ;) (type $_) + i32.const 32 + global.set $~lib/allocator/arena/startOffset + global.get $~lib/allocator/arena/startOffset + global.set $~lib/allocator/arena/offset + ) + (func $null (; 1 ;) (type $_) + nop + ) +) diff --git a/tests/compiler/simd.ts b/tests/compiler/simd.ts new file mode 100644 index 00000000..677f9585 --- /dev/null +++ b/tests/compiler/simd.ts @@ -0,0 +1,424 @@ +// hint: asc tests/compiler/simd --enable simd --validate + +import "allocator/arena"; + +function test_v128(): void { + // equality and inequality + assert( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + == // i8x16.all_true(i8x16.eq(lhs, rhs)) + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + ); + assert( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + != // i8x16.any_true(i8x16.ne(lhs, rhs)) + v128(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + ); + // bitwise + assert( + v128.and( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + ) == + v128(1, 0, 1, 0, 1, 0, 1, 0, 1, 0 , 1 , 0 , 1 , 0 , 1 , 0) + ); + assert( + v128.or( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + ) == + v128(1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 17) + ); + assert( + v128.xor( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + ) == + v128(0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17) + ); + assert( + v128.not( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + ) == + v128(-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17) + ); + assert( + v128.bitselect( + v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + v128(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), + v128(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + ) == + v128(16, 2, 14, 4, 12, 6, 10, 8, 8, 10, 6, 12, 4, 14, 2, 16), + ); + // generic operations are tested by the aliases below already + + // FIXME: node/nightly currently fails to validate this. works in node/v8-canary. + // var base = memory.allocate(256); + // v128.store(base, v128.load(base + 16, 32), 64); +} + +function test_i8x16(): void { + var a = i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 127); + assert(a == v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 127)); + var b = i8x16.splat(1); + assert(b == v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); + var c = i8x16.add(a, b); + assert(c == i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -128)); + assert(i8x16.sub(c, b) == a); + assert(i8x16.mul(c, b) == c); + assert( + i8x16.neg(a) + == + i8x16(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -127) + ); + assert(i8x16.extract_lane_s(c, 0) == 2); + assert(i8x16.extract_lane_s(c, 15) == -128); + assert(i8x16.extract_lane_u(c, 15) == 128); + assert( + i8x16.replace_lane(c, 15, 17) + == + i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) + ); + assert( + v128.shuffle(a, b, 0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31) + == + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 1, 1, 1, 1, 1, 1, 1, 1) + ); + assert( + i8x16.add_saturate_s( + i8x16(126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127), + i8x16.splat(2) + ) == i8x16.splat(127) + ); + assert( + i8x16.add_saturate_u( + i8x16(-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + i8x16.splat(2) + ) == i8x16.splat(-1) + ); + assert( + i8x16.sub_saturate_s( + i8x16(-127, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128), + i8x16.splat(2) + ) == i8x16.splat(-128) + ); + assert( + i8x16.sub_saturate_u( + i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + i8x16.splat(2) + ) == i8x16.splat(0) + ); + assert(i8x16.shl(i8x16.splat(1), 1) == i8x16.splat(2)); + assert(i8x16.shr_s(i8x16.splat(-2), 1) == i8x16.splat(-1)); + assert(i8x16.shr_u(i8x16.splat(-1), 1) == i8x16.splat(127)); + assert(i8x16.any_true(i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == true); + assert(i8x16.all_true(i8x16.splat(1)) == true); + var one = i8x16.replace_lane(i8x16.splat(0), 0, 1); + var negOne = i8x16.replace_lane(i8x16.splat(0), 0, -1); + var only1st = negOne; + var excl1st = v128.not(negOne); + assert(i8x16.eq(negOne, one) == excl1st); + assert(i8x16.ne(negOne, one) == only1st); + assert(i8x16.lt_s(negOne, one) == only1st); + assert(i8x16.lt_u(one, negOne) == only1st); + assert(i8x16.le_s(one, negOne) == excl1st); + assert(i8x16.le_u(negOne, one) == excl1st); + assert(i8x16.gt_s(one, negOne) == only1st); + assert(i8x16.gt_u(negOne, one) == only1st); + assert(i8x16.ge_s(negOne, one) == excl1st); + assert(i8x16.ge_u(one, negOne) == excl1st); +} + +function test_i16x8(): void { + var a = i16x8(1, 2, 3, 4, 5, 6, 7, 32767); + assert(a == v128(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, 127)); + var b = i16x8.splat(1); + assert(b == v128(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)); + var c = i16x8.add(a, b); + assert(c == i16x8(2, 3, 4, 5, 6, 7, 8, -32768)); + assert(i16x8.sub(c, b) == a); + assert(i16x8.mul(c, b) == c); + assert( + i16x8.neg(a) + == + i16x8(-1, -2, -3, -4, -5, -6, -7, -32767) + ); + assert(i16x8.extract_lane_s(c, 0) == 2); + assert(i16x8.extract_lane_s(c, 7) == -32768); + assert(i16x8.extract_lane_u(c, 7) == 32768); + assert( + i16x8.replace_lane(c, 7, 9) + == + i16x8(2, 3, 4, 5, 6, 7, 8, 9) + ); + assert( + v128.shuffle(a, b, 0, 1, 2, 3, 12, 13, 14, 15) + == + i16x8(1, 2, 3, 4, 1, 1, 1, 1) + ); + assert( + i16x8.add_saturate_s( + i16x8(32766, 32767, 32767, 32767, 32767, 32767, 32767, 32767), + i16x8.splat(2) + ) == i16x8.splat(32767) + ); + assert( + i16x8.add_saturate_u( + i16x8(-2, -1, -1, -1, -1, -1, -1, -1), + i16x8.splat(2) + ) == i16x8.splat(-1) + ); + assert( + i16x8.sub_saturate_s( + i16x8(-32767, -32768, -32768, -32768, -32768, -32768, -32768, -32768), + i16x8.splat(2) + ) == i16x8.splat(-32768) + ); + assert( + i16x8.sub_saturate_u( + i16x8(1, 0, 0, 0, 0, 0, 0, 0), + i16x8.splat(2) + ) == i16x8.splat(0) + ); + assert(i16x8.shl(i16x8.splat(1), 1) == i16x8.splat(2)); + assert(i16x8.shr_s(i16x8.splat(-2), 1) == i16x8.splat(-1)); + assert(i16x8.shr_u(i16x8.splat(-1), 1) == i16x8.splat(32767)); + assert(i16x8.any_true(i16x8(1, 0, 0, 0, 0, 0, 0, 0)) == true); + assert(i16x8.all_true(i16x8.splat(1)) == true); + var one = i16x8.replace_lane(i16x8.splat(0), 0, 1); + var negOne = i16x8.replace_lane(i16x8.splat(0), 0, -1); + var only1st = negOne; + var excl1st = v128.not(negOne); + assert(i16x8.eq(negOne, one) == excl1st); + assert(i16x8.ne(negOne, one) == only1st); + assert(i16x8.lt_s(negOne, one) == only1st); + assert(i16x8.lt_u(one, negOne) == only1st); + assert(i16x8.le_s(one, negOne) == excl1st); + assert(i16x8.le_u(negOne, one) == excl1st); + assert(i16x8.gt_s(one, negOne) == only1st); + assert(i16x8.gt_u(negOne, one) == only1st); + assert(i16x8.ge_s(negOne, one) == excl1st); + assert(i16x8.ge_u(one, negOne) == excl1st); +} + +function test_i32x4(): void { + var a = i32x4(1, 2, 3, 2147483647); + assert(a == v128(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, 127)); + var b = i32x4.splat(1); + assert(b == v128(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)); + var c = i32x4.add(a, b); + assert(c == i32x4(2, 3, 4, -2147483648)); + assert(i32x4.sub(c, b) == a); + assert(i32x4.mul(c, b) == c); + assert( + i32x4.neg(a) + == + i32x4(-1, -2, -3, -2147483647) + ); + assert(i32x4.extract_lane(c, 0) == 2); + assert(i32x4.extract_lane(c, 3) == -2147483648); + assert( + i32x4.replace_lane(c, 3, 5) + == + i32x4(2, 3, 4, 5) + ); + assert( + v128.shuffle(a, b, 0, 1, 6, 7) + == + i32x4(1, 2, 1, 1) + ); + assert(i32x4.shl(i32x4.splat(1), 1) == i32x4.splat(2)); + assert(i32x4.shr_s(i32x4.splat(-2), 1) == i32x4.splat(-1)); + assert(i32x4.shr_u(i32x4.splat(-1), 1) == i32x4.splat(2147483647)); + assert(i32x4.any_true(i32x4(1, 0, 0, 0)) == true); + assert(i32x4.all_true(i32x4.splat(1)) == true); + var one = i32x4.replace_lane(i32x4.splat(0), 0, 1); + var negOne = i32x4.replace_lane(i32x4.splat(0), 0, -1); + var only1st = negOne; + var excl1st = v128.not(negOne); + assert(i32x4.eq(negOne, one) == excl1st); + assert(i32x4.ne(negOne, one) == only1st); + assert(i32x4.lt_s(negOne, one) == only1st); + assert(i32x4.lt_u(one, negOne) == only1st); + assert(i32x4.le_s(one, negOne) == excl1st); + assert(i32x4.le_u(negOne, one) == excl1st); + assert(i32x4.gt_s(one, negOne) == only1st); + assert(i32x4.gt_u(negOne, one) == only1st); + assert(i32x4.ge_s(negOne, one) == excl1st); + assert(i32x4.ge_u(one, negOne) == excl1st); + assert( + i32x4.trunc_s_f32x4_sat(f32x4.splat(-1.5)) + == + i32x4.splat(-1) + ); + assert( + i32x4.trunc_u_f32x4_sat(f32x4.splat(-1.5)) + == + i32x4.splat(0) + ); +} + +function test_i64x2(): void { + var a = i64x2(1, 9223372036854775807); + assert(a == v128(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 127)); + var b = i64x2.splat(1); + assert(b == v128(1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + var c = i64x2.add(a, b); + assert(c == i64x2(2, -9223372036854775808)); + assert(i64x2.sub(c, b) == a); + assert( + i64x2.neg(a) + == + i64x2(-1, -9223372036854775807) + ); + assert(i64x2.extract_lane(c, 0) == 2); + assert(i64x2.extract_lane(c, 1) == -9223372036854775808); + assert( + i64x2.replace_lane(c, 1, 3) + == + i64x2(2, 3) + ); + assert( + v128.shuffle(a, b, 0, 3) + == + i64x2(1, 1) + ); + assert(i64x2.shl(i64x2.splat(1), 1) == i64x2.splat(2)); + assert(i64x2.shr_s(i64x2.splat(-2), 1) == i64x2.splat(-1)); + assert(i64x2.shr_u(i64x2.splat(-1), 1) == i64x2.splat(9223372036854775807)); + assert(i64x2.any_true(i64x2(1, 0)) == true); + assert(i64x2.all_true(i64x2.splat(1)) == true); + assert( + i64x2.trunc_s_f64x2_sat(f64x2.splat(-1.5)) + == + i64x2.splat(-1) + ); + assert( + i64x2.trunc_u_f64x2_sat(f64x2.splat(-1.5)) + == + i64x2.splat(0) + ); +} + +function test_f32x4(): void { + var a = f32x4(1.5, 2.5, 3.5, 4.5); + assert(a == v128(0, 0, -64, 63, 0, 0, 32, 64, 0, 0, 96, 64, 0, 0, -112, 64)); + var b = f32x4.splat(1.0); + assert(b == v128(0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63)); + var c = f32x4.add(a, b); + assert(c == f32x4(2.5, 3.5, 4.5, 5.5)); + assert(f32x4.sub(c, b) == a); + assert(f32x4.mul(c, b) == c); + var d = f32x4.mul(a, a); + assert(f32x4.div(d, a) == a); + assert(f32x4.mul(d, a) != a); + assert(f32x4.neg(a) == f32x4(-1.5, -2.5, -3.5, -4.5)); + assert(f32x4.extract_lane(c, 0) == 2.5); + assert(f32x4.extract_lane(c, 3) == 5.5); + assert( + f32x4.replace_lane(c, 3, 6.5) + == + f32x4(2.5, 3.5, 4.5, 6.5) + ); + assert( + v128.shuffle(a, b, 0, 1, 6, 7) + == + f32x4(1.5, 2.5, 1.0, 1.0) + ); + var one = f32x4.replace_lane(f32x4.splat(0), 0, 1); + var negOne = f32x4.replace_lane(f32x4.splat(0), 0, -1); + var only1st = i32x4(-1, 0, 0, 0); + var excl1st = i32x4(0, -1, -1, -1); + assert(f32x4.eq(negOne, one) == excl1st); + assert(f32x4.ne(negOne, one) == only1st); + assert(f32x4.lt(negOne, one) == only1st); + assert(f32x4.le(one, negOne) == excl1st); + assert(f32x4.gt(one, negOne) == only1st); + assert(f32x4.ge(negOne, one) == excl1st); + assert(f32x4.min(negOne, one) == negOne); + assert(f32x4.max(negOne, one) == one); + assert(f32x4.abs(negOne) == one); + assert(f32x4.sqrt(f32x4(4.0, 9.0, 16.0, 25.0)) == f32x4(2.0, 3.0, 4.0, 5.0)); + assert( + f32x4.convert_s_i32x4(i32x4.splat(-1)) + == + f32x4.splat(-1.0) + ); + assert( + f32x4.convert_u_i32x4(i32x4.splat(-1)) + == + f32x4.splat(4294967296.0) + ); +} + +function test_f64x2(): void { + var a = f64x2(1.5, 2.5); + assert(a == v128(0, 0, 0, 0, 0, 0, -8, 63, 0, 0, 0, 0, 0, 0, 4, 64)); + var b = f64x2.splat(1.0); + assert(b == v128(0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, -16, 63)); + var c = f64x2.add(a, b); + assert(c == f64x2(2.5, 3.5)); + assert(f64x2.sub(c, b) == a); + assert(f64x2.mul(c, b) == c); + var d = f64x2.mul(a, a); + assert(f64x2.div(d, a) == a); + assert(f64x2.mul(d, a) != a); + assert(f64x2.neg(a) == f64x2(-1.5, -2.5)); + assert(f64x2.extract_lane(c, 0) == 2.5); + assert(f64x2.extract_lane(c, 1) == 3.5); + assert( + f64x2.replace_lane(c, 1, 4.5) + == + f64x2(2.5, 4.5) + ); + assert( + v128.shuffle(a, b, 0, 3) + == + f64x2(1.5, 1.0) + ); + var one = f64x2.replace_lane(f64x2.splat(0), 0, 1); + var negOne = f64x2.replace_lane(f64x2.splat(0), 0, -1); + var only1st = i64x2(-1, 0); + var excl1st = i64x2(0, -1); + assert(f64x2.eq(negOne, one) == excl1st); + assert(f64x2.ne(negOne, one) == only1st); + assert(f64x2.lt(negOne, one) == only1st); + assert(f64x2.le(one, negOne) == excl1st); + assert(f64x2.gt(one, negOne) == only1st); + assert(f64x2.ge(negOne, one) == excl1st); + assert(f64x2.min(negOne, one) == negOne); + assert(f64x2.max(negOne, one) == one); + assert(f64x2.abs(negOne) == one); + assert(f64x2.sqrt(f64x2(4.0, 9.0)) == f64x2(2.0, 3.0)); + assert( + f64x2.convert_s_i64x2(i64x2.splat(-1)) + == + f64x2.splat(-1.0) + ); + assert( + f64x2.convert_u_i64x2(i64x2.splat(-1)) + == + f64x2.splat(18446744073709551615.0) + ); +} + +function test_v8x16(): void { + var a = v128( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + var b = v128(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + assert( + v8x16.shuffle(a, b, 0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31) + == + v128(0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31) + ); +} + +if (ASC_FEATURE_SIMD) { + test_v128(); + test_i8x16(); + test_i16x8(); + test_i32x4(); + test_i64x2(); + test_f32x4(); + test_f64x2(); + test_v8x16(); +} diff --git a/tests/compiler/simd.untouched.wat b/tests/compiler/simd.untouched.wat new file mode 100644 index 00000000..09216fb8 --- /dev/null +++ b/tests/compiler/simd.untouched.wat @@ -0,0 +1,2896 @@ +(module + (type $_ (func)) + (type $iiii_ (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "\07\00\00\00s\00i\00m\00d\00.\00t\00s\00") + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (global $~lib/ASC_FEATURE_SIMD i32 (i32.const 0)) + (global $~lib/memory/HEAP_BASE i32 (i32.const 28)) + (export "memory" (memory $0)) + (export "table" (table $0)) + (start $start) + (func $start:~lib/allocator/arena (; 1 ;) (type $_) + global.get $~lib/memory/HEAP_BASE + i32.const 7 + i32.add + i32.const 7 + i32.const -1 + i32.xor + i32.and + global.set $~lib/allocator/arena/startOffset + global.get $~lib/allocator/arena/startOffset + global.set $~lib/allocator/arena/offset + ) + (func $simd/test_v128 (; 2 ;) (type $_) + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 7 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x2 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + i8x16.ne + i8x16.any_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 12 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 + v128.and + v128.const i32 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 18 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 + v128.or + v128.const i32 0x1 0x3 0x3 0x5 0x5 0x7 0x7 0x9 0x9 0xb 0xb 0xd 0xd 0xf 0xf 0x11 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 25 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 + v128.xor + v128.const i32 0x0 0x3 0x2 0x5 0x4 0x7 0x6 0x9 0x8 0xb 0xa 0xd 0xc 0xf 0xe 0x11 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 32 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.not + v128.const i32 0xfe 0xfd 0xfc 0xfb 0xfa 0xf9 0xf8 0xf7 0xf6 0xf5 0xf4 0xf3 0xf2 0xf1 0xf0 0xef + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 39 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 + v128.const i32 0x10 0xf 0xe 0xd 0xc 0xb 0xa 0x9 0x8 0x7 0x6 0x5 0x4 0x3 0x2 0x1 + v128.const i32 0x0 0xff 0x0 0xff 0x0 0xff 0x0 0xff 0x0 0xff 0x0 0xff 0x0 0xff 0x0 0xff + v128.bitselect + v128.const i32 0x10 0x2 0xe 0x4 0xc 0x6 0xa 0x8 0x8 0xa 0x6 0xc 0x4 0xe 0x2 0x10 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 45 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_i8x16 (; 3 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + (local $3 v128) + (local $4 v128) + (local $5 v128) + (local $6 v128) + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x7f + local.set $0 + local.get $0 + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x7f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 62 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i8x16.splat + local.set $1 + local.get $1 + v128.const i32 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 64 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + i8x16.add + local.set $2 + local.get $2 + v128.const i32 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 66 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i8x16.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 67 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i8x16.mul + local.get $2 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 68 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + i8x16.neg + v128.const i32 0xff 0xfe 0xfd 0xfc 0xfb 0xfa 0xf9 0xf8 0xf7 0xf6 0xf5 0xf4 0xf3 0xf2 0xf1 0x81 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 69 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i8x16.extract_lane_s 0 + i32.const 24 + i32.shl + i32.const 24 + i32.shr_s + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 74 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i8x16.extract_lane_s 15 + i32.const 24 + i32.shl + i32.const 24 + i32.shr_s + i32.const -128 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 75 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i8x16.extract_lane_u 15 + i32.const 255 + i32.and + i32.const 128 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 76 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i32.const 17 + i8x16.replace_lane 15 + v128.const i32 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 0x11 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 77 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 82 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x7e 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f + i32.const 2 + i8x16.splat + i8x16.add_saturate_s + i32.const 127 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 87 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0xfe 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + i32.const 2 + i8x16.splat + i8x16.add_saturate_u + i32.const -1 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 93 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x81 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + i32.const 2 + i8x16.splat + i8x16.sub_saturate_s + i32.const -128 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 99 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i32.const 2 + i8x16.splat + i8x16.sub_saturate_u + i32.const 0 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 105 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i8x16.splat + i32.const 1 + i8x16.shl + i32.const 2 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 111 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -2 + i8x16.splat + i32.const 1 + i8x16.shr_s + i32.const -1 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 112 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -1 + i8x16.splat + i32.const 1 + i8x16.shr_u + i32.const 127 + i8x16.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 113 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i8x16.any_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 114 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i8x16.splat + i8x16.all_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 115 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 0 + i8x16.splat + i32.const 1 + i8x16.replace_lane 0 + local.set $3 + i32.const 0 + i8x16.splat + i32.const -1 + i8x16.replace_lane 0 + local.set $4 + local.get $4 + local.set $5 + local.get $4 + v128.not + local.set $6 + local.get $4 + local.get $3 + i8x16.eq + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 120 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i8x16.ne + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 121 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i8x16.lt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 122 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i8x16.lt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 123 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i8x16.le_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 124 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i8x16.le_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 125 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i8x16.gt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 126 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i8x16.gt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 127 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i8x16.ge_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 128 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i8x16.ge_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 129 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_i16x8 (; 4 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + (local $3 v128) + (local $4 v128) + (local $5 v128) + (local $6 v128) + v128.const i32 0x1 0x0 0x2 0x0 0x3 0x0 0x4 0x0 0x5 0x0 0x6 0x0 0x7 0x0 0xff 0x7f + local.set $0 + local.get $0 + v128.const i32 0x1 0x0 0x2 0x0 0x3 0x0 0x4 0x0 0x5 0x0 0x6 0x0 0x7 0x0 0xff 0x7f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 134 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i16x8.splat + local.set $1 + local.get $1 + v128.const i32 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 136 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + i16x8.add + local.set $2 + local.get $2 + v128.const i32 0x2 0x0 0x3 0x0 0x4 0x0 0x5 0x0 0x6 0x0 0x7 0x0 0x8 0x0 0x0 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 138 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i16x8.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 139 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i16x8.mul + local.get $2 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 140 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + i16x8.neg + v128.const i32 0xff 0xff 0xfe 0xff 0xfd 0xff 0xfc 0xff 0xfb 0xff 0xfa 0xff 0xf9 0xff 0x1 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 141 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i16x8.extract_lane_s 0 + i32.const 16 + i32.shl + i32.const 16 + i32.shr_s + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 146 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i16x8.extract_lane_s 7 + i32.const 16 + i32.shl + i32.const 16 + i32.shr_s + i32.const -32768 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 147 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i16x8.extract_lane_u 7 + i32.const 65535 + i32.and + i32.const 32768 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 148 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i32.const 9 + i16x8.replace_lane 7 + v128.const i32 0x2 0x0 0x3 0x0 0x4 0x0 0x5 0x0 0x6 0x0 0x7 0x0 0x8 0x0 0x9 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 149 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x1 0x0 0x2 0x0 0x3 0x0 0x4 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 154 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0xfe 0x7f 0xff 0x7f 0xff 0x7f 0xff 0x7f 0xff 0x7f 0xff 0x7f 0xff 0x7f 0xff 0x7f + i32.const 2 + i16x8.splat + i16x8.add_saturate_s + i32.const 32767 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 159 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0xfe 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + i32.const 2 + i16x8.splat + i16x8.add_saturate_u + i32.const -1 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 165 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x80 0x0 0x80 0x0 0x80 0x0 0x80 0x0 0x80 0x0 0x80 0x0 0x80 0x0 0x80 + i32.const 2 + i16x8.splat + i16x8.sub_saturate_s + i32.const -32768 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 171 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i32.const 2 + i16x8.splat + i16x8.sub_saturate_u + i32.const 0 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 177 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i16x8.splat + i32.const 1 + i16x8.shl + i32.const 2 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 183 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -2 + i16x8.splat + i32.const 1 + i16x8.shr_s + i32.const -1 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 184 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -1 + i16x8.splat + i32.const 1 + i16x8.shr_u + i32.const 32767 + i16x8.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 185 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i16x8.any_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 186 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i16x8.splat + i16x8.all_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 187 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 0 + i16x8.splat + i32.const 1 + i16x8.replace_lane 0 + local.set $3 + i32.const 0 + i16x8.splat + i32.const -1 + i16x8.replace_lane 0 + local.set $4 + local.get $4 + local.set $5 + local.get $4 + v128.not + local.set $6 + local.get $4 + local.get $3 + i16x8.eq + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 192 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i16x8.ne + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 193 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i16x8.lt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 194 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i16x8.lt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 195 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i16x8.le_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 196 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i16x8.le_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 197 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i16x8.gt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 198 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i16x8.gt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 199 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i16x8.ge_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 200 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i16x8.ge_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 201 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_i32x4 (; 5 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + (local $3 v128) + (local $4 v128) + (local $5 v128) + (local $6 v128) + v128.const i32 0x1 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0xff 0xff 0xff 0x7f + local.set $0 + local.get $0 + v128.const i32 0x1 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0xff 0xff 0xff 0x7f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 206 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32x4.splat + local.set $1 + local.get $1 + v128.const i32 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 208 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + i32x4.add + local.set $2 + local.get $2 + v128.const i32 0x2 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 210 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i32x4.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 211 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i32x4.mul + local.get $2 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 212 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + i32x4.neg + v128.const i32 0xff 0xff 0xff 0xff 0xfe 0xff 0xff 0xff 0xfd 0xff 0xff 0xff 0x1 0x0 0x0 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 213 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i32x4.extract_lane 0 + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 218 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i32x4.extract_lane 3 + i32.const -2147483648 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 219 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i32.const 5 + i32x4.replace_lane 3 + v128.const i32 0x2 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x4 0x0 0x0 0x0 0x5 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 220 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x1 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 225 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32x4.splat + i32.const 1 + i32x4.shl + i32.const 2 + i32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 230 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -2 + i32x4.splat + i32.const 1 + i32x4.shr_s + i32.const -1 + i32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 231 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -1 + i32x4.splat + i32.const 1 + i32x4.shr_u + i32.const 2147483647 + i32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 232 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i32x4.any_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 233 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 1 + i32x4.splat + i32x4.all_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 234 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const 0 + i32x4.splat + i32.const 1 + i32x4.replace_lane 0 + local.set $3 + i32.const 0 + i32x4.splat + i32.const -1 + i32x4.replace_lane 0 + local.set $4 + local.get $4 + local.set $5 + local.get $4 + v128.not + local.set $6 + local.get $4 + local.get $3 + i32x4.eq + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 239 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i32x4.ne + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 240 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i32x4.lt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 241 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i32x4.lt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 242 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i32x4.le_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 243 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i32x4.le_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 244 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i32x4.gt_s + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 245 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i32x4.gt_u + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 246 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $3 + i32x4.ge_s + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 247 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $4 + i32x4.ge_u + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 248 + i32.const 2 + call $~lib/env/abort + unreachable + end + f32.const -1.5 + f32x4.splat + i32x4.trunc_sat_f32x4_s + i32.const -1 + i32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 249 + i32.const 2 + call $~lib/env/abort + unreachable + end + f32.const -1.5 + f32x4.splat + i32x4.trunc_sat_f32x4_u + i32.const 0 + i32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 254 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_i64x2 (; 6 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x7f + local.set $0 + local.get $0 + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x7f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 263 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const 1 + i64x2.splat + local.set $1 + local.get $1 + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 265 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + i64x2.add + local.set $2 + local.get $2 + v128.const i32 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 267 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i64x2.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 268 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + i64x2.neg + v128.const i32 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x80 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 269 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i64x2.extract_lane 0 + i64.const 2 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 274 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i64x2.extract_lane 1 + i64.const -9223372036854775808 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 275 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + i64.const 3 + i64x2.replace_lane 1 + v128.const i32 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 276 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 281 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const 1 + i64x2.splat + i32.const 1 + i64x2.shl + i64.const 2 + i64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 286 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const -2 + i64x2.splat + i32.const 1 + i64x2.shr_s + i64.const -1 + i64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 287 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const -1 + i64x2.splat + i32.const 1 + i64x2.shr_u + i64.const 9223372036854775807 + i64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 288 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i64x2.any_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 289 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const 1 + i64x2.splat + i64x2.all_true + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 290 + i32.const 2 + call $~lib/env/abort + unreachable + end + f64.const -1.5 + f64x2.splat + i64x2.trunc_sat_f64x2_s + i64.const -1 + i64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 291 + i32.const 2 + call $~lib/env/abort + unreachable + end + f64.const -1.5 + f64x2.splat + i64x2.trunc_sat_f64x2_u + i64.const 0 + i64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 296 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_f32x4 (; 7 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + (local $3 v128) + (local $4 v128) + (local $5 v128) + (local $6 v128) + (local $7 v128) + v128.const i32 0x0 0x0 0xc0 0x3f 0x0 0x0 0x20 0x40 0x0 0x0 0x60 0x40 0x0 0x0 0x90 0x40 + local.set $0 + local.get $0 + v128.const i32 0x0 0x0 0xc0 0x3f 0x0 0x0 0x20 0x40 0x0 0x0 0x60 0x40 0x0 0x0 0x90 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 305 + i32.const 2 + call $~lib/env/abort + unreachable + end + f32.const 1 + f32x4.splat + local.set $1 + local.get $1 + v128.const i32 0x0 0x0 0x80 0x3f 0x0 0x0 0x80 0x3f 0x0 0x0 0x80 0x3f 0x0 0x0 0x80 0x3f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 307 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + f32x4.add + local.set $2 + local.get $2 + v128.const i32 0x0 0x0 0x20 0x40 0x0 0x0 0x60 0x40 0x0 0x0 0x90 0x40 0x0 0x0 0xb0 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 309 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + f32x4.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 310 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + f32x4.mul + local.get $2 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 311 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $0 + f32x4.mul + local.set $3 + local.get $3 + local.get $0 + f32x4.div + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 313 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $0 + f32x4.mul + local.get $0 + i8x16.ne + i8x16.any_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 314 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + f32x4.neg + v128.const i32 0x0 0x0 0xc0 0xbf 0x0 0x0 0x20 0xc0 0x0 0x0 0x60 0xc0 0x0 0x0 0x90 0xc0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 315 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f32x4.extract_lane 0 + f32.const 2.5 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 316 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f32x4.extract_lane 3 + f32.const 5.5 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 317 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f32.const 6.5 + f32x4.replace_lane 3 + v128.const i32 0x0 0x0 0x20 0x40 0x0 0x0 0x60 0x40 0x0 0x0 0x90 0x40 0x0 0x0 0xd0 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 318 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x0 0x0 0xc0 0x3f 0x0 0x0 0x20 0x40 0x0 0x0 0x80 0x3f 0x0 0x0 0x80 0x3f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 323 + i32.const 2 + call $~lib/env/abort + unreachable + end + f32.const 0 + f32x4.splat + f32.const 1 + f32x4.replace_lane 0 + local.set $4 + f32.const 0 + f32x4.splat + f32.const -1 + f32x4.replace_lane 0 + local.set $5 + v128.const i32 0xff 0xff 0xff 0xff 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + local.set $6 + v128.const i32 0x0 0x0 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + local.set $7 + local.get $5 + local.get $4 + f32x4.eq + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 332 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f32x4.ne + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 333 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f32x4.lt + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 334 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $5 + f32x4.le + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 335 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $5 + f32x4.gt + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 336 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f32x4.ge + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 337 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f32x4.min + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 338 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f32x4.max + local.get $4 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 339 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + f32x4.abs + local.get $4 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 340 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x0 0x0 0x80 0x40 0x0 0x0 0x10 0x41 0x0 0x0 0x80 0x41 0x0 0x0 0xc8 0x41 + f32x4.sqrt + v128.const i32 0x0 0x0 0x0 0x40 0x0 0x0 0x40 0x40 0x0 0x0 0x80 0x40 0x0 0x0 0xa0 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 341 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -1 + i32x4.splat + f32x4.convert_i32x4_s + f32.const -1 + f32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 342 + i32.const 2 + call $~lib/env/abort + unreachable + end + i32.const -1 + i32x4.splat + f32x4.convert_i32x4_u + f32.const 4294967296 + f32x4.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 347 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_f64x2 (; 8 ;) (type $_) + (local $0 v128) + (local $1 v128) + (local $2 v128) + (local $3 v128) + (local $4 v128) + (local $5 v128) + (local $6 v128) + (local $7 v128) + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xf8 0x3f 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x40 + local.set $0 + local.get $0 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xf8 0x3f 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 356 + i32.const 2 + call $~lib/env/abort + unreachable + end + f64.const 1 + f64x2.splat + local.set $1 + local.get $1 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xf0 0x3f 0x0 0x0 0x0 0x0 0x0 0x0 0xf0 0x3f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 358 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + f64x2.add + local.set $2 + local.get $2 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x40 0x0 0x0 0x0 0x0 0x0 0x0 0xc 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 360 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + f64x2.sub + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 361 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + f64x2.mul + local.get $2 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 362 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $0 + f64x2.mul + local.set $3 + local.get $3 + local.get $0 + f64x2.div + local.get $0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 364 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $3 + local.get $0 + f64x2.mul + local.get $0 + i8x16.ne + i8x16.any_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 365 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + f64x2.neg + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xf8 0xbf 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0xc0 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 366 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f64x2.extract_lane 0 + f64.const 2.5 + f64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 367 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f64x2.extract_lane 1 + f64.const 3.5 + f64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 368 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $2 + f64.const 4.5 + f64x2.replace_lane 1 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x40 0x0 0x0 0x0 0x0 0x0 0x0 0x12 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 369 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $0 + local.get $1 + v8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xf8 0x3f 0x0 0x0 0x0 0x0 0x0 0x0 0xf0 0x3f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 374 + i32.const 2 + call $~lib/env/abort + unreachable + end + f64.const 0 + f64x2.splat + f64.const 1 + f64x2.replace_lane 0 + local.set $4 + f64.const 0 + f64x2.splat + f64.const -1 + f64x2.replace_lane 0 + local.set $5 + v128.const i32 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + local.set $6 + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + local.set $7 + local.get $5 + local.get $4 + f64x2.eq + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 383 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f64x2.ne + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 384 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f64x2.lt + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 385 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $5 + f64x2.le + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 386 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $4 + local.get $5 + f64x2.gt + local.get $6 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 387 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f64x2.ge + local.get $7 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 388 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f64x2.min + local.get $5 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 389 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + local.get $4 + f64x2.max + local.get $4 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 390 + i32.const 2 + call $~lib/env/abort + unreachable + end + local.get $5 + f64x2.abs + local.get $4 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 391 + i32.const 2 + call $~lib/env/abort + unreachable + end + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0x10 0x40 0x0 0x0 0x0 0x0 0x0 0x0 0x22 0x40 + f64x2.sqrt + v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x40 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x40 + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 392 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const -1 + i64x2.splat + f64x2.convert_i64x2_s + f64.const -1 + f64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 393 + i32.const 2 + call $~lib/env/abort + unreachable + end + i64.const -1 + i64x2.splat + f64x2.convert_i64x2_u + f64.const 18446744073709551615 + f64x2.splat + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 398 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $simd/test_v8x16 (; 9 ;) (type $_) + (local $0 v128) + (local $1 v128) + v128.const i32 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf + local.set $0 + v128.const i32 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f + local.set $1 + local.get $0 + local.get $1 + v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31 + v128.const i32 0x0 0x11 0x2 0x13 0x4 0x15 0x6 0x17 0x8 0x19 0xa 0x1b 0xc 0x1d 0xe 0x1f + i8x16.eq + i8x16.all_true + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 408 + i32.const 2 + call $~lib/env/abort + unreachable + end + ) + (func $start:simd (; 10 ;) (type $_) + call $start:~lib/allocator/arena + block + call $simd/test_v128 + call $simd/test_i8x16 + call $simd/test_i16x8 + call $simd/test_i32x4 + call $simd/test_i64x2 + call $simd/test_f32x4 + call $simd/test_f64x2 + call $simd/test_v8x16 + end + ) + (func $start (; 11 ;) (type $_) + call $start:simd + ) + (func $null (; 12 ;) (type $_) + ) +) diff --git a/tests/compiler/std/simd.optimized.wat b/tests/compiler/std/simd.optimized.wat new file mode 100644 index 00000000..da2a6760 --- /dev/null +++ b/tests/compiler/std/simd.optimized.wat @@ -0,0 +1,11 @@ +(module + (type $_ (func)) + (memory $0 0) + (table $0 1 funcref) + (elem (i32.const 0) $null) + (export "memory" (memory $0)) + (export "table" (table $0)) + (func $null (; 0 ;) (type $_) + nop + ) +) diff --git a/tests/compiler/std/simd.ts b/tests/compiler/std/simd.ts new file mode 100644 index 00000000..600fb1af --- /dev/null +++ b/tests/compiler/std/simd.ts @@ -0,0 +1,31 @@ +// hint: asc tests/compiler/std/simd --enable simd --validate + +@sealed +class I8x16 { + + @inline static from(vec: v128): I8x16 { + return changetype(vec); + } + + // TODO: not possible due to arguments becoming locals, no longer being compile-time constants + // @inline constructor( + // a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8 + // ) { + // return changetype(i8x16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); + // } + private constructor() { unreachable(); } + + @inline @operator("+") + add(vec: I8x16): I8x16 { + return changetype(v128.add(changetype(this), changetype(vec))); + } +} + +function test_I8x16(): void { + var a = I8x16.from(i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); + var c = a + a; +} + +if (ASC_FEATURE_SIMD) { + test_I8x16(); +} diff --git a/tests/compiler/std/simd.untouched.wat b/tests/compiler/std/simd.untouched.wat new file mode 100644 index 00000000..b91c32fb --- /dev/null +++ b/tests/compiler/std/simd.untouched.wat @@ -0,0 +1,12 @@ +(module + (type $_ (func)) + (memory $0 0) + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $~lib/ASC_FEATURE_SIMD i32 (i32.const 0)) + (global $~lib/memory/HEAP_BASE i32 (i32.const 8)) + (export "memory" (memory $0)) + (export "table" (table $0)) + (func $null (; 0 ;) (type $_) + ) +) diff --git a/tests/features.json b/tests/features.json new file mode 100644 index 00000000..cc995dbe --- /dev/null +++ b/tests/features.json @@ -0,0 +1,10 @@ +{ + "simd": { + "asc_flags": [ + "--enable simd" + ], + "v8_flags": [ + "--experimental-wasm-simd" + ] + } +}