diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 9e73f26377d..6dd7a91d671 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -1414,6 +1414,36 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return binary_numeric_operation>(configuration); case Instructions::i8x16_ge_u.value(): return binary_numeric_operation>(configuration); + case Instructions::i8x16_abs.value(): + return unary_operation>(configuration); + case Instructions::i8x16_neg.value(): + return unary_operation>(configuration); + case Instructions::i8x16_all_true.value(): + return unary_operation>(configuration); + case Instructions::i8x16_popcnt.value(): + return unary_operation>(configuration); + case Instructions::i8x16_add.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_sub.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_avgr_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_add_sat_s.value(): + return binary_numeric_operation, MakeSigned>>(configuration); + case Instructions::i8x16_add_sat_u.value(): + return binary_numeric_operation, MakeUnsigned>>(configuration); + case Instructions::i8x16_sub_sat_s.value(): + return binary_numeric_operation, MakeSigned>>(configuration); + case Instructions::i8x16_sub_sat_u.value(): + return binary_numeric_operation, MakeUnsigned>>(configuration); + case Instructions::i8x16_min_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_min_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_max_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i8x16_max_u.value(): + return binary_numeric_operation>(configuration); case Instructions::i16x8_eq.value(): return binary_numeric_operation>(configuration); case Instructions::i16x8_ne.value(): @@ -1434,6 +1464,56 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return binary_numeric_operation>(configuration); case Instructions::i16x8_ge_u.value(): return binary_numeric_operation>(configuration); + case Instructions::i16x8_abs.value(): + return unary_operation>(configuration); + case Instructions::i16x8_neg.value(): + return unary_operation>(configuration); + case Instructions::i16x8_all_true.value(): + return unary_operation>(configuration); + case Instructions::i16x8_add.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_sub.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_mul.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_avgr_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_add_sat_s.value(): + return binary_numeric_operation, MakeSigned>>(configuration); + case Instructions::i16x8_add_sat_u.value(): + return binary_numeric_operation, MakeUnsigned>>(configuration); + case Instructions::i16x8_sub_sat_s.value(): + return binary_numeric_operation, MakeSigned>>(configuration); + case Instructions::i16x8_sub_sat_u.value(): + return binary_numeric_operation, MakeUnsigned>>(configuration); + case Instructions::i16x8_min_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_min_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_max_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_max_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_extend_low_i8x16_s.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extend_high_i8x16_s.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extend_low_i8x16_u.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extend_high_i8x16_u.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): + return unary_operation>(configuration); + case Instructions::i16x8_extmul_low_i8x16_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_extmul_high_i8x16_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_extmul_low_i8x16_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i16x8_extmul_high_i8x16_u.value(): + return binary_numeric_operation>(configuration); case Instructions::i32x4_eq.value(): return binary_numeric_operation>(configuration); case Instructions::i32x4_ne.value(): @@ -1454,6 +1534,86 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return binary_numeric_operation>(configuration); case Instructions::i32x4_ge_u.value(): return binary_numeric_operation>(configuration); + case Instructions::i32x4_abs.value(): + return unary_operation>(configuration); + case Instructions::i32x4_neg.value(): + return unary_operation>(configuration); + case Instructions::i32x4_all_true.value(): + return unary_operation>(configuration); + case Instructions::i32x4_add.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_sub.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_mul.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_min_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_min_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_max_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_max_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_extend_low_i16x8_s.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extend_high_i16x8_s.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extend_low_i16x8_u.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extend_high_i16x8_u.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): + return unary_operation>(configuration); + case Instructions::i32x4_extmul_low_i16x8_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_extmul_high_i16x8_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_extmul_low_i16x8_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i32x4_extmul_high_i16x8_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_eq.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_ne.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_lt_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_gt_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_le_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_ge_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_abs.value(): + return unary_operation>(configuration); + case Instructions::i64x2_neg.value(): + return unary_operation>(configuration); + case Instructions::i64x2_all_true.value(): + return unary_operation>(configuration); + case Instructions::i64x2_add.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_sub.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_mul.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_extend_low_i32x4_s.value(): + return unary_operation>(configuration); + case Instructions::i64x2_extend_high_i32x4_s.value(): + return unary_operation>(configuration); + case Instructions::i64x2_extend_low_i32x4_u.value(): + return unary_operation>(configuration); + case Instructions::i64x2_extend_high_i32x4_u.value(): + return unary_operation>(configuration); + case Instructions::i64x2_extmul_low_i32x4_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_extmul_high_i32x4_s.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_extmul_low_i32x4_u.value(): + return binary_numeric_operation>(configuration); + case Instructions::i64x2_extmul_high_i32x4_u.value(): + return binary_numeric_operation>(configuration); case Instructions::f32x4_eq.value(): return binary_numeric_operation>(configuration); case Instructions::f32x4_ne.value(): @@ -1569,95 +1729,16 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi case Instructions::v128_load64_zero.value(): case Instructions::f32x4_demote_f64x2_zero.value(): case Instructions::f64x2_promote_low_f32x4.value(): - case Instructions::i8x16_abs.value(): - case Instructions::i8x16_neg.value(): - case Instructions::i8x16_popcnt.value(): - case Instructions::i8x16_all_true.value(): case Instructions::i8x16_bitmask.value(): case Instructions::i8x16_narrow_i16x8_s.value(): case Instructions::i8x16_narrow_i16x8_u.value(): - case Instructions::i8x16_add.value(): - case Instructions::i8x16_add_sat_s.value(): - case Instructions::i8x16_add_sat_u.value(): - case Instructions::i8x16_sub.value(): - case Instructions::i8x16_sub_sat_s.value(): - case Instructions::i8x16_sub_sat_u.value(): - case Instructions::i8x16_min_s.value(): - case Instructions::i8x16_min_u.value(): - case Instructions::i8x16_max_s.value(): - case Instructions::i8x16_max_u.value(): - case Instructions::i8x16_avgr_u.value(): - case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): - case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): - case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): - case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): - case Instructions::i16x8_abs.value(): - case Instructions::i16x8_neg.value(): case Instructions::i16x8_q15mulr_sat_s.value(): - case Instructions::i16x8_all_true.value(): case Instructions::i16x8_bitmask.value(): case Instructions::i16x8_narrow_i32x4_s.value(): case Instructions::i16x8_narrow_i32x4_u.value(): - case Instructions::i16x8_extend_low_i8x16_s.value(): - case Instructions::i16x8_extend_high_i8x16_s.value(): - case Instructions::i16x8_extend_low_i8x16_u.value(): - case Instructions::i16x8_extend_high_i8x16_u.value(): - case Instructions::i16x8_add.value(): - case Instructions::i16x8_add_sat_s.value(): - case Instructions::i16x8_add_sat_u.value(): - case Instructions::i16x8_sub.value(): - case Instructions::i16x8_sub_sat_s.value(): - case Instructions::i16x8_sub_sat_u.value(): - case Instructions::i16x8_mul.value(): - case Instructions::i16x8_min_s.value(): - case Instructions::i16x8_min_u.value(): - case Instructions::i16x8_max_s.value(): - case Instructions::i16x8_max_u.value(): - case Instructions::i16x8_avgr_u.value(): - case Instructions::i16x8_extmul_low_i8x16_s.value(): - case Instructions::i16x8_extmul_high_i8x16_s.value(): - case Instructions::i16x8_extmul_low_i8x16_u.value(): - case Instructions::i16x8_extmul_high_i8x16_u.value(): - case Instructions::i32x4_abs.value(): - case Instructions::i32x4_neg.value(): - case Instructions::i32x4_all_true.value(): case Instructions::i32x4_bitmask.value(): - case Instructions::i32x4_extend_low_i16x8_s.value(): - case Instructions::i32x4_extend_high_i16x8_s.value(): - case Instructions::i32x4_extend_low_i16x8_u.value(): - case Instructions::i32x4_extend_high_i16x8_u.value(): - case Instructions::i32x4_add.value(): - case Instructions::i32x4_sub.value(): - case Instructions::i32x4_mul.value(): - case Instructions::i32x4_min_s.value(): - case Instructions::i32x4_min_u.value(): - case Instructions::i32x4_max_s.value(): - case Instructions::i32x4_max_u.value(): case Instructions::i32x4_dot_i16x8_s.value(): - case Instructions::i32x4_extmul_low_i16x8_s.value(): - case Instructions::i32x4_extmul_high_i16x8_s.value(): - case Instructions::i32x4_extmul_low_i16x8_u.value(): - case Instructions::i32x4_extmul_high_i16x8_u.value(): - case Instructions::i64x2_abs.value(): - case Instructions::i64x2_neg.value(): - case Instructions::i64x2_all_true.value(): case Instructions::i64x2_bitmask.value(): - case Instructions::i64x2_extend_low_i32x4_s.value(): - case Instructions::i64x2_extend_high_i32x4_s.value(): - case Instructions::i64x2_extend_low_i32x4_u.value(): - case Instructions::i64x2_extend_high_i32x4_u.value(): - case Instructions::i64x2_sub.value(): - case Instructions::i64x2_mul.value(): - case Instructions::i64x2_eq.value(): - case Instructions::i64x2_ne.value(): - case Instructions::i64x2_lt_s.value(): - case Instructions::i64x2_gt_s.value(): - case Instructions::i64x2_le_s.value(): - case Instructions::i64x2_ge_s.value(): - case Instructions::i64x2_extmul_low_i32x4_s.value(): - case Instructions::i64x2_extmul_high_i32x4_s.value(): - case Instructions::i64x2_extmul_low_i32x4_u.value(): - case Instructions::i64x2_extmul_high_i32x4_u.value(): case Instructions::i32x4_trunc_sat_f32x4_s.value(): case Instructions::i32x4_trunc_sat_f32x4_u.value(): case Instructions::f32x4_convert_i32x4_s.value(): diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h index 62c635ca999..5698b39386e 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Operators.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Operators.h @@ -82,6 +82,16 @@ struct Modulo { static StringView name() { return "%"sv; } }; +struct Average { + template + auto operator()(Lhs lhs, Rhs rhs) const + { + return static_cast((lhs + rhs + 1) / 2); + } + + static StringView name() { return "avgr"sv; } +}; + struct BitShiftLeft { template auto operator()(Lhs lhs, Rhs rhs) const { return lhs << (rhs % (sizeof(lhs) * 8)); } @@ -138,6 +148,33 @@ struct BitRotateRight { static StringView name() { return "rotate_right"sv; } }; +template typename SetSign = MakeSigned> +struct VectorAllTrue { + auto operator()(u128 c) const + { + using ElementType = NativeIntegralType<128 / VectorSize>; + + auto any_false = bit_cast>(c) == 0; + return bit_cast(any_false) == 0; + } + + static StringView name() + { + switch (VectorSize) { + case 16: + return "vec(8x16).all_true"sv; + case 8: + return "vec(16x8).all_true"sv; + case 4: + return "vec(32x4).all_true"sv; + case 2: + return "vec(64x2).all_true"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + template struct VectorShiftLeft { auto operator()(u128 lhs, i32 rhs) const @@ -457,7 +494,7 @@ struct PopCount { template auto operator()(Lhs lhs) const { - if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8) + if constexpr (sizeof(Lhs) == 1 || sizeof(Lhs) == 2 || sizeof(Lhs) == 4 || sizeof(Lhs) == 8) return popcount(MakeUnsigned(lhs)); else VERIFY_NOT_REACHED(); @@ -495,6 +532,194 @@ struct Ceil { static StringView name() { return "ceil"sv; } }; +template typename SetSign = MakeSigned> +struct VectorIntegerExtOpPairwise { + auto operator()(u128 c) const + { + using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>; + using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>; + auto vector = bit_cast(c); + VectorResult result; + Op op; + + // FIXME: Find a way to not loop here + for (size_t i = 0; i < VectorSize; ++i) { + result[i] = op(vector[i * 2], vector[(i * 2) + 1]); + } + + return bit_cast(result); + } + + static StringView name() + { + switch (VectorSize) { + case 8: + return "vec(16x8).ext_op_pairwise(8x16)"sv; + case 4: + return "vec(32x4).ext_op_pairwise(16x8)"sv; + case 2: + return "vec(64x2).ext_op_pairwise(32x4)"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + +enum class VectorExt { + High, + Low, +}; + +template typename SetSign = MakeSigned> +struct VectorIntegerExt { + auto operator()(u128 c) const + { + using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>; + using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>; + auto vector = bit_cast(c); + VectorResult result; + + // FIXME: Find a way to not loop here + for (size_t i = 0; i < VectorSize; ++i) { + if constexpr (Mode == VectorExt::High) + result[i] = vector[VectorSize + i]; + else if constexpr (Mode == VectorExt::Low) + result[i] = vector[i]; + else + VERIFY_NOT_REACHED(); + } + + return bit_cast(result); + } + + static StringView name() + { + switch (VectorSize) { + case 8: + return "vec(16x8).ext(8x16)"sv; + case 4: + return "vec(32x4).ext(16x8)"sv; + case 2: + return "vec(64x2).ext(32x4)"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + +template typename SetSign = MakeSigned> +struct VectorIntegerExtOp { + auto operator()(u128 lhs, u128 rhs) const + { + using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>; + using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>; + auto first = bit_cast(lhs); + auto second = bit_cast(rhs); + VectorResult result; + Op op; + + using ResultType = SetSign>; + // FIXME: Find a way to not loop here + for (size_t i = 0; i < VectorSize; ++i) { + if constexpr (Mode == VectorExt::High) { + ResultType a = first[VectorSize + i]; + ResultType b = second[VectorSize + i]; + result[i] = op(a, b); + } else if constexpr (Mode == VectorExt::Low) { + ResultType a = first[i]; + ResultType b = second[i]; + result[i] = op(a, b); + } else + VERIFY_NOT_REACHED(); + } + + return bit_cast(result); + } + + static StringView name() + { + switch (VectorSize) { + case 8: + return "vec(16x8).ext_op(8x16)"sv; + case 4: + return "vec(32x4).ext_op(16x8)"sv; + case 2: + return "vec(64x2).ext_op(32x4)"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + +template typename SetSign = MakeSigned> +struct VectorIntegerBinaryOp { + auto operator()(u128 lhs, u128 rhs) const + { + using VectorType = NativeVectorType<128 / VectorSize, VectorSize, SetSign>; + auto first = bit_cast(lhs); + auto second = bit_cast(rhs); + VectorType result; + Op op; + + // FIXME: Find a way to not loop here + for (size_t i = 0; i < VectorSize; ++i) { + result[i] = op(first[i], second[i]); + } + + return bit_cast(result); + } + + static StringView name() + { + switch (VectorSize) { + case 16: + return "vec(8x16).binary_op"sv; + case 8: + return "vec(16x8).binary_op"sv; + case 4: + return "vec(32x4).binary_op"sv; + case 2: + return "vec(64x2).binary_op"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + +template typename SetSign = MakeSigned> +struct VectorIntegerUnaryOp { + auto operator()(u128 lhs) const + { + using VectorType = NativeVectorType<128 / VectorSize, VectorSize, SetSign>; + auto value = bit_cast(lhs); + VectorType result; + Op op; + + // FIXME: Find a way to not loop here + for (size_t i = 0; i < VectorSize; ++i) { + result[i] = op(value[i]); + } + + return bit_cast(result); + } + + static StringView name() + { + switch (VectorSize) { + case 16: + return "vec(8x16).unary_op"sv; + case 8: + return "vec(16x8).unary_op"sv; + case 4: + return "vec(32x4).unary_op"sv; + case 2: + return "vec(64x2).unary_op"sv; + default: + VERIFY_NOT_REACHED(); + } + } +}; + template struct VectorFloatBinaryOp { auto operator()(u128 lhs, u128 rhs) const @@ -528,11 +753,11 @@ struct VectorFloatUnaryOp { auto operator()(u128 lhs) const { using VectorType = NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>; - auto first = bit_cast(lhs); + auto value = bit_cast(lhs); VectorType result; Op op; for (size_t i = 0; i < VectorSize; ++i) { - result[i] = op(first[i]); + result[i] = op(value[i]); } return bit_cast(result); } @@ -762,4 +987,26 @@ struct SaturatingTruncate { static StringView name() { return "truncate.saturating"sv; } }; +template +struct SaturatingOp { + template + ResultT operator()(Lhs lhs, Rhs rhs) const + { + Op op; + + double result = op(lhs, rhs); + + if (result <= static_cast(NumericLimits::min())) { + return NumericLimits::min(); + } + + if (result >= static_cast(NumericLimits::max())) { + return NumericLimits::max(); + } + + return static_cast(result); + } + + static StringView name() { return "saturating_op"sv; } +}; }