[ubsan] Fix numerical overflows in wasm
Mostly signed integer overflows, and a few cases of double division by zero (which is defined by IEEE-754 to return Infinity (or NaN for 0/0) but is UB in C++). Bug: v8:3770 Change-Id: Id92725b0ac57cb357978124a3dc6f477430bc97d Reviewed-on: https://chromium-review.googlesource.com/c/1403133 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#58696}
This commit is contained in:
parent
f9a858fc96
commit
40ac5a39fc
@ -12,6 +12,7 @@
|
||||
#include "src/asmjs/asm-js.h"
|
||||
#include "src/asmjs/asm-types.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/flags.h"
|
||||
#include "src/parsing/scanner.h"
|
||||
#include "src/wasm/wasm-limits.h"
|
||||
@ -1564,7 +1565,8 @@ AsmType* AsmJsParser::UnaryExpression() {
|
||||
if (CheckForUnsigned(&uvalue)) {
|
||||
// TODO(bradnelson): was supposed to be 0x7FFFFFFF, check errata.
|
||||
if (uvalue <= 0x80000000) {
|
||||
current_function_builder_->EmitI32Const(-static_cast<int32_t>(uvalue));
|
||||
current_function_builder_->EmitI32Const(
|
||||
base::NegateWithWraparound(static_cast<int32_t>(uvalue)));
|
||||
} else {
|
||||
FAILn("Integer numeric literal out of range.");
|
||||
}
|
||||
|
@ -2665,6 +2665,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
}
|
||||
|
||||
// Typecheck the topmost {num_returns} values on the stack.
|
||||
if (num_returns == 0) return true;
|
||||
// This line requires num_returns > 0.
|
||||
Value* stack_values = &*(stack_.end() - num_returns);
|
||||
for (uint32_t i = 0; i < num_returns; ++i) {
|
||||
auto& val = stack_values[i];
|
||||
|
@ -233,13 +233,13 @@ uint32_t word64_popcnt_wrapper(Address data) {
|
||||
uint32_t word32_rol_wrapper(Address data) {
|
||||
uint32_t input = ReadUnalignedValue<uint32_t>(data);
|
||||
uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
|
||||
return (input << shift) | (input >> (32 - shift));
|
||||
return (input << shift) | (input >> ((32 - shift) & 31));
|
||||
}
|
||||
|
||||
uint32_t word32_ror_wrapper(Address data) {
|
||||
uint32_t input = ReadUnalignedValue<uint32_t>(data);
|
||||
uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
|
||||
return (input >> shift) | (input << (32 - shift));
|
||||
return (input >> shift) | (input << ((32 - shift) & 31));
|
||||
}
|
||||
|
||||
void float64_pow_wrapper(Address data) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "src/wasm/wasm-interpreter.h"
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/boxed-float.h"
|
||||
#include "src/compiler/wasm-compiler.h"
|
||||
#include "src/conversions.h"
|
||||
@ -289,23 +290,19 @@ inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
|
||||
}
|
||||
|
||||
inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
|
||||
uint32_t shift = (b & 0x1F);
|
||||
return (a >> shift) | (a << (32 - shift));
|
||||
return (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F));
|
||||
}
|
||||
|
||||
inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
|
||||
uint32_t shift = (b & 0x1F);
|
||||
return (a << shift) | (a >> (32 - shift));
|
||||
return (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F));
|
||||
}
|
||||
|
||||
inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
|
||||
uint32_t shift = (b & 0x3F);
|
||||
return (a >> shift) | (a << (64 - shift));
|
||||
return (a >> (b & 0x3F)) | (a << ((64 - b) & 0x3F));
|
||||
}
|
||||
|
||||
inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
|
||||
uint32_t shift = (b & 0x3F);
|
||||
return (a << shift) | (a >> (64 - shift));
|
||||
return (a << (b & 0x3F)) | (a >> ((64 - b) & 0x3F));
|
||||
}
|
||||
|
||||
inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
|
||||
@ -1737,9 +1734,9 @@ class ThreadImpl {
|
||||
BINOP_CASE(F32x4Mul, f32x4, float4, 4, a * b)
|
||||
BINOP_CASE(F32x4Min, f32x4, float4, 4, a < b ? a : b)
|
||||
BINOP_CASE(F32x4Max, f32x4, float4, 4, a > b ? a : b)
|
||||
BINOP_CASE(I32x4Add, i32x4, int4, 4, a + b)
|
||||
BINOP_CASE(I32x4Sub, i32x4, int4, 4, a - b)
|
||||
BINOP_CASE(I32x4Mul, i32x4, int4, 4, a * b)
|
||||
BINOP_CASE(I32x4Add, i32x4, int4, 4, base::AddWithWraparound(a, b))
|
||||
BINOP_CASE(I32x4Sub, i32x4, int4, 4, base::SubWithWraparound(a, b))
|
||||
BINOP_CASE(I32x4Mul, i32x4, int4, 4, base::MulWithWraparound(a, b))
|
||||
BINOP_CASE(I32x4MinS, i32x4, int4, 4, a < b ? a : b)
|
||||
BINOP_CASE(I32x4MinU, i32x4, int4, 4,
|
||||
static_cast<uint32_t>(a) < static_cast<uint32_t>(b) ? a : b)
|
||||
@ -1749,9 +1746,9 @@ class ThreadImpl {
|
||||
BINOP_CASE(S128And, i32x4, int4, 4, a & b)
|
||||
BINOP_CASE(S128Or, i32x4, int4, 4, a | b)
|
||||
BINOP_CASE(S128Xor, i32x4, int4, 4, a ^ b)
|
||||
BINOP_CASE(I16x8Add, i16x8, int8, 8, a + b)
|
||||
BINOP_CASE(I16x8Sub, i16x8, int8, 8, a - b)
|
||||
BINOP_CASE(I16x8Mul, i16x8, int8, 8, a * b)
|
||||
BINOP_CASE(I16x8Add, i16x8, int8, 8, base::AddWithWraparound(a, b))
|
||||
BINOP_CASE(I16x8Sub, i16x8, int8, 8, base::SubWithWraparound(a, b))
|
||||
BINOP_CASE(I16x8Mul, i16x8, int8, 8, base::MulWithWraparound(a, b))
|
||||
BINOP_CASE(I16x8MinS, i16x8, int8, 8, a < b ? a : b)
|
||||
BINOP_CASE(I16x8MinU, i16x8, int8, 8,
|
||||
static_cast<uint16_t>(a) < static_cast<uint16_t>(b) ? a : b)
|
||||
@ -1762,9 +1759,9 @@ class ThreadImpl {
|
||||
BINOP_CASE(I16x8AddSaturateU, i16x8, int8, 8, SaturateAdd<uint16_t>(a, b))
|
||||
BINOP_CASE(I16x8SubSaturateS, i16x8, int8, 8, SaturateSub<int16_t>(a, b))
|
||||
BINOP_CASE(I16x8SubSaturateU, i16x8, int8, 8, SaturateSub<uint16_t>(a, b))
|
||||
BINOP_CASE(I8x16Add, i8x16, int16, 16, a + b)
|
||||
BINOP_CASE(I8x16Sub, i8x16, int16, 16, a - b)
|
||||
BINOP_CASE(I8x16Mul, i8x16, int16, 16, a * b)
|
||||
BINOP_CASE(I8x16Add, i8x16, int16, 16, base::AddWithWraparound(a, b))
|
||||
BINOP_CASE(I8x16Sub, i8x16, int16, 16, base::SubWithWraparound(a, b))
|
||||
BINOP_CASE(I8x16Mul, i8x16, int16, 16, base::MulWithWraparound(a, b))
|
||||
BINOP_CASE(I8x16MinS, i8x16, int16, 16, a < b ? a : b)
|
||||
BINOP_CASE(I8x16MinU, i8x16, int16, 16,
|
||||
static_cast<uint8_t>(a) < static_cast<uint8_t>(b) ? a : b)
|
||||
@ -1792,12 +1789,12 @@ class ThreadImpl {
|
||||
}
|
||||
UNOP_CASE(F32x4Abs, f32x4, float4, 4, std::abs(a))
|
||||
UNOP_CASE(F32x4Neg, f32x4, float4, 4, -a)
|
||||
UNOP_CASE(F32x4RecipApprox, f32x4, float4, 4, 1.0f / a)
|
||||
UNOP_CASE(F32x4RecipSqrtApprox, f32x4, float4, 4, 1.0f / std::sqrt(a))
|
||||
UNOP_CASE(I32x4Neg, i32x4, int4, 4, -a)
|
||||
UNOP_CASE(F32x4RecipApprox, f32x4, float4, 4, base::Recip(a))
|
||||
UNOP_CASE(F32x4RecipSqrtApprox, f32x4, float4, 4, base::RecipSqrt(a))
|
||||
UNOP_CASE(I32x4Neg, i32x4, int4, 4, base::NegateWithWraparound(a))
|
||||
UNOP_CASE(S128Not, i32x4, int4, 4, ~a)
|
||||
UNOP_CASE(I16x8Neg, i16x8, int8, 8, -a)
|
||||
UNOP_CASE(I8x16Neg, i8x16, int16, 16, -a)
|
||||
UNOP_CASE(I16x8Neg, i16x8, int8, 8, base::NegateWithWraparound(a))
|
||||
UNOP_CASE(I8x16Neg, i8x16, int16, 16, base::NegateWithWraparound(a))
|
||||
#undef UNOP_CASE
|
||||
#define CMPOP_CASE(op, name, stype, out_stype, count, expr) \
|
||||
case kExpr##op: { \
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "src/api-natives.h"
|
||||
#include "src/assert-scope.h"
|
||||
#include "src/ast/ast.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/execution.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/heap/factory.h"
|
||||
@ -1408,7 +1409,7 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
return;
|
||||
}
|
||||
int64_t old_size = old_buffer->byte_length() / i::wasm::kWasmPageSize;
|
||||
int64_t new_size64 = old_size + delta_size;
|
||||
int64_t new_size64 = base::AddWithWraparound(old_size, delta_size);
|
||||
if (delta_size < 0 || max_size64 < new_size64 || new_size64 < old_size) {
|
||||
thrower.RangeError(new_size64 < old_size ? "trying to shrink memory"
|
||||
: "maximum memory size exceeded");
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
@ -104,7 +105,9 @@ TEST(TestCWasmEntryArgPassing_int32) {
|
||||
CWasmEntryArgTester<int32_t, int32_t> tester(
|
||||
{// Return 2*<0> + 1.
|
||||
WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
|
||||
[](int32_t a) { return 2 * a + 1; });
|
||||
[](int32_t a) {
|
||||
return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
|
||||
});
|
||||
|
||||
FOR_INT32_INPUTS(v) { tester.CheckCall(*v); }
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/objects-inl.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
@ -53,7 +54,9 @@ WASM_EXEC_TEST(I64Add) {
|
||||
WasmRunner<int64_t, int64_t, int64_t> r(execution_tier);
|
||||
BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); }
|
||||
FOR_INT64_INPUTS(j) {
|
||||
CHECK_EQ(base::AddWithWraparound(*i, *j), r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +78,9 @@ WASM_EXEC_TEST(I64Sub) {
|
||||
WasmRunner<int64_t, int64_t, int64_t> r(execution_tier);
|
||||
BUILD(r, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) { CHECK_EQ(*i - *j, r.Call(*i, *j)); }
|
||||
FOR_INT64_INPUTS(j) {
|
||||
CHECK_EQ(base::SubWithWraparound(*i, *j), r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +99,8 @@ WASM_EXEC_TEST(I64AddUseOnlyLowWord) {
|
||||
WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) {
|
||||
CHECK_EQ(static_cast<int32_t>(*i + *j), r.Call(*i, *j));
|
||||
CHECK_EQ(static_cast<int32_t>(base::AddWithWraparound(*i, *j)),
|
||||
r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,7 +111,8 @@ WASM_EXEC_TEST(I64SubUseOnlyLowWord) {
|
||||
WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) {
|
||||
CHECK_EQ(static_cast<int32_t>(*i - *j), r.Call(*i, *j));
|
||||
CHECK_EQ(static_cast<int32_t>(base::SubWithWraparound(*i, *j)),
|
||||
r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,7 +123,8 @@ WASM_EXEC_TEST(I64MulUseOnlyLowWord) {
|
||||
WASM_I64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) {
|
||||
CHECK_EQ(static_cast<int32_t>(*i * *j), r.Call(*i, *j));
|
||||
CHECK_EQ(static_cast<int32_t>(base::MulWithWraparound(*i, *j)),
|
||||
r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,7 +135,7 @@ WASM_EXEC_TEST(I64ShlUseOnlyLowWord) {
|
||||
WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) {
|
||||
int32_t expected = static_cast<int32_t>((*i) << (*j & 0x3F));
|
||||
int32_t expected = static_cast<int32_t>(base::ShlWithWraparound(*i, *j));
|
||||
CHECK_EQ(expected, r.Call(*i, *j));
|
||||
}
|
||||
}
|
||||
@ -1230,7 +1238,8 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
|
||||
WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO)));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
|
||||
int64_t expected = base::MulWithWraparound(static_cast<int64_t>(*i),
|
||||
int64_t{0x300010001L});
|
||||
r.builder().WriteMemory(&memory[0], expected);
|
||||
CHECK_EQ(expected, r.Call());
|
||||
}
|
||||
@ -1255,7 +1264,8 @@ WASM_EXEC_TEST(F64ReinterpretI64) {
|
||||
WASM_GET_LOCAL(0));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
|
||||
int64_t expected = base::MulWithWraparound(static_cast<int64_t>(*i),
|
||||
int64_t{0x300010001L});
|
||||
CHECK_EQ(expected, r.Call(expected));
|
||||
CHECK_EQ(expected, r.builder().ReadMemory<int64_t>(&memory[0]));
|
||||
}
|
||||
|
@ -2,8 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||
@ -50,22 +53,29 @@ typedef int8_t (*Int8ShiftOp)(int8_t, int);
|
||||
void RunWasm_##name##_Impl(LowerSimd lower_simd, ExecutionTier execution_tier)
|
||||
|
||||
// Generic expected value functions.
|
||||
template <typename T>
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type>
|
||||
T Negate(T a) {
|
||||
return -a;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
// For signed integral types, use base::AddWithWraparound.
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type>
|
||||
T Add(T a, T b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
// For signed integral types, use base::SubWithWraparound.
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type>
|
||||
T Sub(T a, T b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
// For signed integral types, use base::MulWithWraparound.
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
std::is_floating_point<T>::value>::type>
|
||||
T Mul(T a, T b) {
|
||||
return a * b;
|
||||
}
|
||||
@ -243,16 +253,6 @@ T Sqrt(T a) {
|
||||
return std::sqrt(a);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Recip(T a) {
|
||||
return 1.0f / a;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T RecipSqrt(T a) {
|
||||
return 1.0f / std::sqrt(a);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#define WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lane_value, lane_index) \
|
||||
@ -509,13 +509,13 @@ WASM_SIMD_TEST(F32x4Neg) {
|
||||
static const float kApproxError = 0.01f;
|
||||
|
||||
WASM_SIMD_TEST(F32x4RecipApprox) {
|
||||
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipApprox, Recip,
|
||||
kApproxError);
|
||||
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipApprox,
|
||||
base::Recip, kApproxError);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(F32x4RecipSqrtApprox) {
|
||||
RunF32x4UnOpTest(execution_tier, lower_simd, kExprF32x4RecipSqrtApprox,
|
||||
RecipSqrt, kApproxError);
|
||||
base::RecipSqrt, kApproxError);
|
||||
}
|
||||
|
||||
void RunF32x4BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
@ -923,7 +923,8 @@ void RunI32x4UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I32x4Neg) {
|
||||
RunI32x4UnOpTest(execution_tier, lower_simd, kExprI32x4Neg, Negate);
|
||||
RunI32x4UnOpTest(execution_tier, lower_simd, kExprI32x4Neg,
|
||||
base::NegateWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(S128Not) {
|
||||
@ -950,15 +951,18 @@ void RunI32x4BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I32x4Add) {
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Add, Add);
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Add,
|
||||
base::AddWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I32x4Sub) {
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Sub, Sub);
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Sub,
|
||||
base::SubWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I32x4Mul) {
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Mul, Mul);
|
||||
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Mul,
|
||||
base::MulWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I32x4MinS) {
|
||||
@ -1143,7 +1147,8 @@ void RunI16x8UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8Neg) {
|
||||
RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Neg, Negate);
|
||||
RunI16x8UnOpTest(execution_tier, lower_simd, kExprI16x8Neg,
|
||||
base::NegateWithWraparound);
|
||||
}
|
||||
|
||||
// Tests both signed and unsigned conversion from I32x4 (packing).
|
||||
@ -1211,7 +1216,8 @@ void RunI16x8BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8Add) {
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Add, Add);
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Add,
|
||||
base::AddWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8AddSaturateS) {
|
||||
@ -1220,7 +1226,8 @@ WASM_SIMD_TEST(I16x8AddSaturateS) {
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8Sub) {
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Sub, Sub);
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Sub,
|
||||
base::SubWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8SubSaturateS) {
|
||||
@ -1229,7 +1236,8 @@ WASM_SIMD_TEST(I16x8SubSaturateS) {
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8Mul) {
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Mul, Mul);
|
||||
RunI16x8BinOpTest(execution_tier, lower_simd, kExprI16x8Mul,
|
||||
base::MulWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I16x8MinS) {
|
||||
@ -1369,7 +1377,8 @@ void RunI8x16UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16Neg) {
|
||||
RunI8x16UnOpTest(execution_tier, lower_simd, kExprI8x16Neg, Negate);
|
||||
RunI8x16UnOpTest(execution_tier, lower_simd, kExprI8x16Neg,
|
||||
base::NegateWithWraparound);
|
||||
}
|
||||
|
||||
// Tests both signed and unsigned conversion from I16x8 (packing).
|
||||
@ -1439,7 +1448,8 @@ void RunI8x16BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16Add) {
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Add, Add);
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Add,
|
||||
base::AddWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16AddSaturateS) {
|
||||
@ -1448,7 +1458,8 @@ WASM_SIMD_TEST(I8x16AddSaturateS) {
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16Sub) {
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Sub, Sub);
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Sub,
|
||||
base::SubWithWraparound);
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16SubSaturateS) {
|
||||
@ -1549,7 +1560,8 @@ WASM_SIMD_TEST(I8x16LeU) {
|
||||
}
|
||||
|
||||
WASM_SIMD_TEST(I8x16Mul) {
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Mul, Mul);
|
||||
RunI8x16BinOpTest(execution_tier, lower_simd, kExprI8x16Mul,
|
||||
base::MulWithWraparound);
|
||||
}
|
||||
|
||||
void RunI8x16ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/base/platform/elapsed-timer.h"
|
||||
#include "src/utils.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
@ -84,14 +85,14 @@ WASM_EXEC_TEST(Int32Add_P) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
// p0 + 13
|
||||
BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_GET_LOCAL(0)));
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(*i, 13), r.Call(*i)); }
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(Int32Add_P_fallthru) {
|
||||
WasmRunner<int32_t, int32_t> r(execution_tier);
|
||||
// p0 + 13
|
||||
BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_GET_LOCAL(0)));
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(*i + 13, r.Call(*i)); }
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(*i, 13), r.Call(*i)); }
|
||||
}
|
||||
|
||||
static void RunInt32AddTest(ExecutionTier execution_tier, const byte* code,
|
||||
@ -190,9 +191,9 @@ static void TestInt32Binop(ExecutionTier execution_tier, WasmOpcode opcode,
|
||||
[](ctype a, ctype b) -> ctype { return expected; }); \
|
||||
}
|
||||
|
||||
WASM_I32_BINOP_TEST(Add, int32_t, a + b)
|
||||
WASM_I32_BINOP_TEST(Sub, int32_t, a - b)
|
||||
WASM_I32_BINOP_TEST(Mul, int32_t, a* b)
|
||||
WASM_I32_BINOP_TEST(Add, int32_t, base::AddWithWraparound(a, b))
|
||||
WASM_I32_BINOP_TEST(Sub, int32_t, base::SubWithWraparound(a, b))
|
||||
WASM_I32_BINOP_TEST(Mul, int32_t, base::MulWithWraparound(a, b))
|
||||
WASM_I32_BINOP_TEST(DivS, int32_t,
|
||||
(a == kMinInt && b == -1) || b == 0
|
||||
? static_cast<int32_t>(0xDEADBEEF)
|
||||
@ -206,8 +207,8 @@ WASM_I32_BINOP_TEST(Xor, int32_t, a ^ b)
|
||||
WASM_I32_BINOP_TEST(Shl, int32_t, a << (b & 0x1F))
|
||||
WASM_I32_BINOP_TEST(ShrU, uint32_t, a >> (b & 0x1F))
|
||||
WASM_I32_BINOP_TEST(ShrS, int32_t, a >> (b & 0x1F))
|
||||
WASM_I32_BINOP_TEST(Ror, uint32_t, (a >> (b & 0x1F)) | (a << (32 - (b & 0x1F))))
|
||||
WASM_I32_BINOP_TEST(Rol, uint32_t, (a << (b & 0x1F)) | (a >> (32 - (b & 0x1F))))
|
||||
WASM_I32_BINOP_TEST(Ror, uint32_t, (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F)))
|
||||
WASM_I32_BINOP_TEST(Rol, uint32_t, (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F)))
|
||||
WASM_I32_BINOP_TEST(Eq, int32_t, a == b)
|
||||
WASM_I32_BINOP_TEST(Ne, int32_t, a != b)
|
||||
WASM_I32_BINOP_TEST(LtS, int32_t, a < b)
|
||||
@ -3298,9 +3299,11 @@ WASM_EXEC_TEST(I32SubOnDifferentRegisters) {
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(I32MulOnDifferentRegisters) {
|
||||
BinOpOnDifferentRegisters<int32_t>(
|
||||
execution_tier, kWasmI32, ArrayVector(kSome32BitInputs), kExprI32Mul,
|
||||
[](int32_t lhs, int32_t rhs, bool* trap) { return lhs * rhs; });
|
||||
BinOpOnDifferentRegisters<int32_t>(execution_tier, kWasmI32,
|
||||
ArrayVector(kSome32BitInputs), kExprI32Mul,
|
||||
[](int32_t lhs, int32_t rhs, bool* trap) {
|
||||
return base::MulWithWraparound(lhs, rhs);
|
||||
});
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(I32ShlOnDifferentRegisters) {
|
||||
@ -3372,9 +3375,11 @@ WASM_EXEC_TEST(I64SubOnDifferentRegisters) {
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(I64MulOnDifferentRegisters) {
|
||||
BinOpOnDifferentRegisters<int64_t>(
|
||||
execution_tier, kWasmI64, ArrayVector(kSome64BitInputs), kExprI64Mul,
|
||||
[](int64_t lhs, int64_t rhs, bool* trap) { return lhs * rhs; });
|
||||
BinOpOnDifferentRegisters<int64_t>(execution_tier, kWasmI64,
|
||||
ArrayVector(kSome64BitInputs), kExprI64Mul,
|
||||
[](int64_t lhs, int64_t rhs, bool* trap) {
|
||||
return base::MulWithWraparound(lhs, rhs);
|
||||
});
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(I64ShlOnDifferentRegisters) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
@ -100,7 +101,9 @@ TEST(TestArgumentPassing_int32) {
|
||||
WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_GET_LOCAL(0)), WASM_ONE)},
|
||||
{// Call f2 with param <0>.
|
||||
WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())},
|
||||
[](int32_t a) { return 2 * a + 1; });
|
||||
[](int32_t a) {
|
||||
return base::AddWithWraparound(base::MulWithWraparound(2, a), 1);
|
||||
});
|
||||
|
||||
FOR_INT32_INPUTS(v) { helper.CheckCall(*v); }
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "test/unittests/test-utils.h"
|
||||
|
||||
#include "src/base/overflowing-math.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/wasm/decoder.h"
|
||||
#include "test/common/wasm/wasm-macro-gen.h"
|
||||
@ -475,7 +476,8 @@ TEST_F(DecoderTest, ReadU32v_Bits) {
|
||||
// foreach length 1...32
|
||||
for (int i = 1; i <= 32; i++) {
|
||||
uint32_t val = kVals[v];
|
||||
if (i < 32) val &= ((1 << i) - 1);
|
||||
if (i < 32)
|
||||
val &= base::SubWithWraparound(base::ShlWithWraparound(1, i), 1);
|
||||
|
||||
unsigned length = 1 + i / 7;
|
||||
for (unsigned j = 0; j < kMaxSize; j++) {
|
||||
|
Loading…
Reference in New Issue
Block a user