Commit 29e0e8e9 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Int64Lowering of I64Div and I64Rem.

On 32-bit systems these instructions are compiled to calls to
C functions. The TF node for the function call is already generated in
the wasm compiler, the lowering of the I64 parameters is done in the
Int64Lowering. We use the return value of the C function to determine
whether the calculation should trap or not.

R=titzer@chromium.org

Review URL: https://codereview.chromium.org/1804513002

Cr-Commit-Position: refs/heads/master@{#34768}
parent c4c34eba
...@@ -1229,6 +1229,26 @@ ExternalReference ExternalReference::wasm_float64_to_uint64(Isolate* isolate) { ...@@ -1229,6 +1229,26 @@ ExternalReference ExternalReference::wasm_float64_to_uint64(Isolate* isolate) {
Redirect(isolate, FUNCTION_ADDR(wasm::float64_to_uint64_wrapper))); Redirect(isolate, FUNCTION_ADDR(wasm::float64_to_uint64_wrapper)));
} }
ExternalReference ExternalReference::wasm_int64_div(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::int64_div_wrapper)));
}
ExternalReference ExternalReference::wasm_int64_mod(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::int64_mod_wrapper)));
}
ExternalReference ExternalReference::wasm_uint64_div(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::uint64_div_wrapper)));
}
ExternalReference ExternalReference::wasm_uint64_mod(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::uint64_mod_wrapper)));
}
static void f64_acos_wrapper(double* param) { *param = std::acos(*param); } static void f64_acos_wrapper(double* param) { *param = std::acos(*param); }
ExternalReference ExternalReference::f64_acos_wrapper_function( ExternalReference ExternalReference::f64_acos_wrapper_function(
......
...@@ -930,6 +930,10 @@ class ExternalReference BASE_EMBEDDED { ...@@ -930,6 +930,10 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference wasm_float32_to_uint64(Isolate* isolate); static ExternalReference wasm_float32_to_uint64(Isolate* isolate);
static ExternalReference wasm_float64_to_int64(Isolate* isolate); static ExternalReference wasm_float64_to_int64(Isolate* isolate);
static ExternalReference wasm_float64_to_uint64(Isolate* isolate); static ExternalReference wasm_float64_to_uint64(Isolate* isolate);
static ExternalReference wasm_int64_div(Isolate* isolate);
static ExternalReference wasm_int64_mod(Isolate* isolate);
static ExternalReference wasm_uint64_div(Isolate* isolate);
static ExternalReference wasm_uint64_mod(Isolate* isolate);
static ExternalReference f64_acos_wrapper_function(Isolate* isolate); static ExternalReference f64_acos_wrapper_function(Isolate* isolate);
static ExternalReference f64_asin_wrapper_function(Isolate* isolate); static ExternalReference f64_asin_wrapper_function(Isolate* isolate);
......
...@@ -500,9 +500,17 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, ...@@ -500,9 +500,17 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
// kExprI64Sub: // kExprI64Sub:
// kExprI64Mul: // kExprI64Mul:
// kExprI64DivS: // kExprI64DivS:
case wasm::kExprI64DivS:
return BuildI64DivS(left, right);
// kExprI64DivU: // kExprI64DivU:
case wasm::kExprI64DivU:
return BuildI64DivU(left, right);
// kExprI64RemS: // kExprI64RemS:
case wasm::kExprI64RemS:
return BuildI64RemS(left, right);
// kExprI64RemU: // kExprI64RemU:
case wasm::kExprI64RemU:
return BuildI64RemU(left, right);
case wasm::kExprI64Ior: case wasm::kExprI64Ior:
op = m->Word64Or(); op = m->Word64Or();
break; break;
...@@ -568,44 +576,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, ...@@ -568,44 +576,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
case wasm::kExprI64Mul: case wasm::kExprI64Mul:
op = m->Int64Mul(); op = m->Int64Mul();
break; break;
case wasm::kExprI64DivS: {
trap_->ZeroCheck64(kTrapDivByZero, right);
Node* before = *control_;
Node* denom_is_m1;
Node* denom_is_not_m1;
Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
jsgraph()->Int64Constant(-1)),
&denom_is_m1, &denom_is_not_m1);
*control_ = denom_is_m1;
trap_->TrapIfEq64(kTrapDivUnrepresentable, left,
std::numeric_limits<int64_t>::min());
if (*control_ != denom_is_m1) {
*control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
denom_is_not_m1, *control_);
} else {
*control_ = before;
}
return graph()->NewNode(m->Int64Div(), left, right, *control_);
}
case wasm::kExprI64DivU:
op = m->Uint64Div();
return graph()->NewNode(op, left, right,
trap_->ZeroCheck64(kTrapDivByZero, right));
case wasm::kExprI64RemS: {
trap_->ZeroCheck64(kTrapRemByZero, right);
Diamond d(jsgraph()->graph(), jsgraph()->common(),
graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
jsgraph()->Int64Constant(-1)));
Node* rem = graph()->NewNode(m->Int64Mod(), left, right, d.if_false);
return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
rem);
}
case wasm::kExprI64RemU:
op = m->Uint64Mod();
return graph()->NewNode(op, left, right,
trap_->ZeroCheck64(kTrapRemByZero, right));
case wasm::kExprI64Ror: case wasm::kExprI64Ror:
op = m->Word64Ror(); op = m->Word64Ror();
break; break;
...@@ -1774,6 +1744,108 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction( ...@@ -1774,6 +1744,108 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
return load; return load;
} }
Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
MachineType::Int64(), kTrapDivByZero);
}
trap_->ZeroCheck64(kTrapDivByZero, right);
Node* before = *control_;
Node* denom_is_m1;
Node* denom_is_not_m1;
Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
jsgraph()->Int64Constant(-1)),
&denom_is_m1, &denom_is_not_m1);
*control_ = denom_is_m1;
trap_->TrapIfEq64(kTrapDivUnrepresentable, left,
std::numeric_limits<int64_t>::min());
if (*control_ != denom_is_m1) {
*control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
*control_);
} else {
*control_ = before;
}
return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
*control_);
}
Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
MachineType::Int64(), kTrapRemByZero);
}
trap_->ZeroCheck64(kTrapRemByZero, right);
Diamond d(jsgraph()->graph(), jsgraph()->common(),
graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
jsgraph()->Int64Constant(-1)));
Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
d.if_false);
return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
rem);
}
Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
MachineType::Int64(), kTrapDivByZero);
}
return graph()->NewNode(jsgraph()->machine()->Uint64Div(), left, right,
trap_->ZeroCheck64(kTrapDivByZero, right));
}
Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
MachineType::Int64(), kTrapRemByZero);
}
return graph()->NewNode(jsgraph()->machine()->Uint64Mod(), left, right,
trap_->ZeroCheck64(kTrapRemByZero, right));
}
Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
ExternalReference ref,
MachineType result_type, int trap_zero) {
Node* stack_slot_dst = graph()->NewNode(
jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
Node* stack_slot_src = graph()->NewNode(
jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
const Operator* store_op = jsgraph()->machine()->Store(
StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
*effect_ =
graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
left, *effect_, *control_);
*effect_ =
graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
right, *effect_, *control_);
MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
sig_builder.AddReturn(MachineType::Int32());
sig_builder.AddParam(MachineType::Pointer());
sig_builder.AddParam(MachineType::Pointer());
Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
Node* args[] = {function, stack_slot_dst, stack_slot_src};
Node* call = BuildCCall(sig_builder.Build(), args);
// TODO(wasm): This can get simpler if we have a specialized runtime call to
// throw WASM exceptions by trap code instead of by string.
trap_->ZeroCheck32(static_cast<TrapReason>(trap_zero), call);
trap_->TrapIfEq32(kTrapDivUnrepresentable, call, -1);
const Operator* load_op = jsgraph()->machine()->Load(result_type);
Node* load =
graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
*effect_, *control_);
*effect_ = load;
return load;
}
Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
const size_t params = sig->parameter_count(); const size_t params = sig->parameter_count();
const size_t extra = 2; // effect and control inputs. const size_t extra = 2; // effect and control inputs.
......
...@@ -225,6 +225,13 @@ class WasmGraphBuilder { ...@@ -225,6 +225,13 @@ class WasmGraphBuilder {
Node* BuildI64SConvertF64(Node* input); Node* BuildI64SConvertF64(Node* input);
Node* BuildI64UConvertF64(Node* input); Node* BuildI64UConvertF64(Node* input);
Node* BuildI64DivS(Node* left, Node* right);
Node* BuildI64RemS(Node* left, Node* right);
Node* BuildI64DivU(Node* left, Node* right);
Node* BuildI64RemU(Node* left, Node* right);
Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref,
MachineType result_type, int trap_zero);
Node** Realloc(Node** buffer, size_t count) { Node** Realloc(Node** buffer, size_t count) {
Node** buf = Buffer(count); Node** buf = Buffer(count);
if (buf != buffer) memcpy(buf, buffer, count * sizeof(Node*)); if (buf != buffer) memcpy(buf, buffer, count * sizeof(Node*));
......
...@@ -131,6 +131,12 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) { ...@@ -131,6 +131,12 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
"wasm::float64_to_int64_wrapper"); "wasm::float64_to_int64_wrapper");
Add(ExternalReference::wasm_float64_to_uint64(isolate).address(), Add(ExternalReference::wasm_float64_to_uint64(isolate).address(),
"wasm::float64_to_uint64_wrapper"); "wasm::float64_to_uint64_wrapper");
Add(ExternalReference::wasm_int64_div(isolate).address(), "wasm::int64_div");
Add(ExternalReference::wasm_int64_mod(isolate).address(), "wasm::int64_mod");
Add(ExternalReference::wasm_uint64_div(isolate).address(),
"wasm::uint64_div");
Add(ExternalReference::wasm_uint64_mod(isolate).address(),
"wasm::uint64_mod");
Add(ExternalReference::f64_acos_wrapper_function(isolate).address(), Add(ExternalReference::f64_acos_wrapper_function(isolate).address(),
"f64_acos_wrapper"); "f64_acos_wrapper");
Add(ExternalReference::f64_asin_wrapper_function(isolate).address(), Add(ExternalReference::f64_asin_wrapper_function(isolate).address(),
......
...@@ -139,6 +139,41 @@ static int32_t float64_to_uint64_wrapper(double* input, uint64_t* output) { ...@@ -139,6 +139,41 @@ static int32_t float64_to_uint64_wrapper(double* input, uint64_t* output) {
} }
return 0; return 0;
} }
static int32_t int64_div_wrapper(int64_t* dst, int64_t* src) {
if (*src == 0) {
return 0;
}
if (*src == -1 && *dst == std::numeric_limits<int64_t>::min()) {
return -1;
}
*dst /= *src;
return 1;
}
static int32_t int64_mod_wrapper(int64_t* dst, int64_t* src) {
if (*src == 0) {
return 0;
}
*dst %= *src;
return 1;
}
static int32_t uint64_div_wrapper(uint64_t* dst, uint64_t* src) {
if (*src == 0) {
return 0;
}
*dst /= *src;
return 1;
}
static int32_t uint64_mod_wrapper(uint64_t* dst, uint64_t* src) {
if (*src == 0) {
return 0;
}
*dst %= *src;
return 1;
}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -424,6 +424,108 @@ TEST(RunCallFloat64ToUint64) { ...@@ -424,6 +424,108 @@ TEST(RunCallFloat64ToUint64) {
} }
} }
} }
TEST(RunCallInt64Div) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_div(m.isolate());
int64_t dst;
int64_t src;
Node* function = m.ExternalConstant(ref);
m.Return(m.CallCFunction2(MachineType::Int32(), MachineType::Pointer(),
MachineType::Pointer(), function,
m.PointerConstant(&dst), m.PointerConstant(&src)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
dst = *i;
src = *j;
if (src == 0) {
CHECK_EQ(0, m.Call());
} else if (src == -1 && dst == std::numeric_limits<int64_t>::min()) {
CHECK_EQ(-1, m.Call());
} else {
CHECK_EQ(1, m.Call());
CHECK_EQ(*i / *j, dst);
}
}
}
}
TEST(RunCallInt64Mod) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_int64_mod(m.isolate());
int64_t dst;
int64_t src;
Node* function = m.ExternalConstant(ref);
m.Return(m.CallCFunction2(MachineType::Int32(), MachineType::Pointer(),
MachineType::Pointer(), function,
m.PointerConstant(&dst), m.PointerConstant(&src)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
dst = *i;
src = *j;
if (src == 0) {
CHECK_EQ(0, m.Call());
} else {
CHECK_EQ(1, m.Call());
CHECK_EQ(*i % *j, dst);
}
}
}
}
TEST(RunCallUint64Div) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_div(m.isolate());
uint64_t dst;
uint64_t src;
Node* function = m.ExternalConstant(ref);
m.Return(m.CallCFunction2(MachineType::Int32(), MachineType::Pointer(),
MachineType::Pointer(), function,
m.PointerConstant(&dst), m.PointerConstant(&src)));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
dst = *i;
src = *j;
if (src == 0) {
CHECK_EQ(0, m.Call());
} else {
CHECK_EQ(1, m.Call());
CHECK_EQ(*i / *j, dst);
}
}
}
}
TEST(RunCallUint64Mod) {
BufferedRawMachineAssemblerTester<int32_t> m;
ExternalReference ref = ExternalReference::wasm_uint64_mod(m.isolate());
uint64_t dst;
uint64_t src;
Node* function = m.ExternalConstant(ref);
m.Return(m.CallCFunction2(MachineType::Int32(), MachineType::Pointer(),
MachineType::Pointer(), function,
m.PointerConstant(&dst), m.PointerConstant(&src)));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
dst = *i;
src = *j;
if (src == 0) {
CHECK_EQ(0, m.Call());
} else {
CHECK_EQ(1, m.Call());
CHECK_EQ(*i % *j, dst);
}
}
}
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -13,6 +13,16 @@ ...@@ -13,6 +13,16 @@
#include "test/cctest/wasm/test-signatures.h" #include "test/cctest/wasm/test-signatures.h"
#include "test/cctest/wasm/wasm-run-utils.h" #include "test/cctest/wasm/wasm-run-utils.h"
#define CHECK_TRAP32(x) \
CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
#define CHECK_TRAP64(x) \
CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
#define CHECK_TRAP(x) CHECK_TRAP32(x)
#define asi64(x) static_cast<int64_t>(x)
#define asu64(x) static_cast<uint64_t>(x)
#define B2(a, b) kExprBlock, 2, a, b #define B2(a, b) kExprBlock, 2, a, b
#define B1(a) kExprBlock, 1, a #define B1(a) kExprBlock, 1, a
...@@ -38,10 +48,10 @@ ...@@ -38,10 +48,10 @@
V(I64Add, true) \ V(I64Add, true) \
V(I64Sub, false) \ V(I64Sub, false) \
V(I64Mul, false) \ V(I64Mul, false) \
V(I64DivS, false) \ V(I64DivS, true) \
V(I64DivU, false) \ V(I64DivU, true) \
V(I64RemS, false) \ V(I64RemS, true) \
V(I64RemU, false) \ V(I64RemU, true) \
V(I64And, true) \ V(I64And, true) \
V(I64Ior, true) \ V(I64Ior, true) \
V(I64Xor, true) \ V(I64Xor, true) \
...@@ -129,9 +139,144 @@ TEST(Run_WasmI64Add) { ...@@ -129,9 +139,144 @@ TEST(Run_WasmI64Add) {
// kExprI64Sub: // kExprI64Sub:
// kExprI64Mul: // kExprI64Mul:
// kExprI64DivS: // kExprI64DivS:
TEST(Run_WasmI64DivS) {
REQUIRE(I64DivS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
if (*j == 0) {
CHECK_TRAP64(r.Call(*i, *j));
} else if (*j == -1 && *i == std::numeric_limits<int64_t>::min()) {
CHECK_TRAP64(r.Call(*i, *j));
} else {
CHECK_EQ(*i / *j, r.Call(*i, *j));
}
}
}
}
TEST(Run_WasmI64DivS_Trap) {
REQUIRE(I64DivS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(asi64(0), asi64(100)));
CHECK_TRAP64(r.Call(asi64(100), asi64(0)));
CHECK_TRAP64(r.Call(asi64(-1001), asi64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), asi64(-1)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), asi64(0)));
}
TEST(Run_WasmI64DivS_Byzero_Const) {
REQUIRE(I64DivS);
for (int8_t denom = -2; denom < 8; denom++) {
WasmRunner<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (int64_t val = -7; val < 8; val++) {
if (denom == 0) {
CHECK_TRAP64(r.Call(val));
} else {
CHECK_EQ(val / denom, r.Call(val));
}
}
}
}
// kExprI64DivU: // kExprI64DivU:
TEST(Run_WasmI64DivU) {
REQUIRE(I64DivU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
if (*j == 0) {
CHECK_TRAP64(r.Call(*i, *j));
} else {
CHECK_EQ(*i / *j, r.Call(*i, *j));
}
}
}
}
TEST(Run_WasmI64DivU_Trap) {
REQUIRE(I64DivU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(asu64(0), asu64(100)));
CHECK_TRAP64(r.Call(asu64(100), asu64(0)));
CHECK_TRAP64(r.Call(asu64(1001), asu64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<uint64_t>::max(), asu64(0)));
}
TEST(Run_WasmI64DivU_Byzero_Const) {
REQUIRE(I64DivU);
for (uint64_t denom = 0xfffffffffffffffe; denom < 8; denom++) {
WasmRunner<uint64_t> r(MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (uint64_t val = 0xfffffffffffffff0; val < 8; val++) {
if (denom == 0) {
CHECK_TRAP64(r.Call(val));
} else {
CHECK_EQ(val / denom, r.Call(val));
}
}
}
}
// kExprI64RemS: // kExprI64RemS:
TEST(Run_WasmI64RemS) {
REQUIRE(I64RemS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
if (*j == 0) {
CHECK_TRAP64(r.Call(*i, *j));
} else {
CHECK_EQ(*i % *j, r.Call(*i, *j));
}
}
}
}
TEST(Run_WasmI64RemS_Trap) {
REQUIRE(I64RemS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(33, r.Call(asi64(133), asi64(100)));
CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), asi64(-1)));
CHECK_TRAP64(r.Call(asi64(100), asi64(0)));
CHECK_TRAP64(r.Call(asi64(-1001), asi64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), asi64(0)));
}
// kExprI64RemU: // kExprI64RemU:
TEST(Run_WasmI64RemU) {
REQUIRE(I64RemU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64());
BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
if (*j == 0) {
CHECK_TRAP64(r.Call(*i, *j));
} else {
CHECK_EQ(*i % *j, r.Call(*i, *j));
}
}
}
}
TEST(Run_Wasm_I64RemU_Trap) {
REQUIRE(I64RemU);
WasmRunner<uint64_t> r(MachineType::Uint64(), MachineType::Uint64());
BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(17, r.Call(asu64(217), asu64(100)));
CHECK_TRAP64(r.Call(asu64(100), asu64(0)));
CHECK_TRAP64(r.Call(asu64(1001), asu64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<uint64_t>::max(), asu64(0)));
}
// kExprI64And: // kExprI64And:
TEST(Run_Wasm_I64And) { TEST(Run_Wasm_I64And) {
REQUIRE(I64And); REQUIRE(I64And);
...@@ -1023,83 +1168,6 @@ TEST(Run_Wasm_I64UConvertF64b) { ...@@ -1023,83 +1168,6 @@ TEST(Run_Wasm_I64UConvertF64b) {
} }
} }
#define as64(x) static_cast<int64_t>(x)
TEST(Run_WASM_I64DivS_trap) {
REQUIRE(I64DivS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(as64(0), as64(100)));
CHECK_TRAP64(r.Call(as64(100), as64(0)));
CHECK_TRAP64(r.Call(as64(-1001), as64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), as64(-1)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), as64(0)));
}
TEST(Run_WASM_I64RemS_trap) {
REQUIRE(I64RemS);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(33, r.Call(as64(133), as64(100)));
CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), as64(-1)));
CHECK_TRAP64(r.Call(as64(100), as64(0)));
CHECK_TRAP64(r.Call(as64(-1001), as64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), as64(0)));
}
TEST(Run_WASM_I64DivU_trap) {
REQUIRE(I64DivU);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(0, r.Call(as64(0), as64(100)));
CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), as64(-1)));
CHECK_TRAP64(r.Call(as64(100), as64(0)));
CHECK_TRAP64(r.Call(as64(-1001), as64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), as64(0)));
}
TEST(Run_WASM_I64RemU_trap) {
REQUIRE(I64RemU);
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
CHECK_EQ(17, r.Call(as64(217), as64(100)));
CHECK_TRAP64(r.Call(as64(100), as64(0)));
CHECK_TRAP64(r.Call(as64(-1001), as64(0)));
CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), as64(0)));
CHECK_EQ(std::numeric_limits<int64_t>::min(),
r.Call(std::numeric_limits<int64_t>::min(), as64(-1)));
}
TEST(Run_WASM_I64DivS_byzero_const) {
REQUIRE(I64DivS);
for (int8_t denom = -2; denom < 8; denom++) {
WasmRunner<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (int64_t val = -7; val < 8; val++) {
if (denom == 0) {
CHECK_TRAP64(r.Call(val));
} else {
CHECK_EQ(val / denom, r.Call(val));
}
}
}
}
TEST(Run_WASM_I64DivU_byzero_const) {
REQUIRE(I64DivU);
for (uint64_t denom = 0xfffffffffffffffe; denom < 8; denom++) {
WasmRunner<uint64_t> r(MachineType::Uint64());
BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_I64V_1(denom)));
for (uint64_t val = 0xfffffffffffffff0; val < 8; val++) {
if (denom == 0) {
CHECK_TRAP64(r.Call(val));
} else {
CHECK_EQ(val / denom, r.Call(val));
}
}
}
}
TEST(Run_Wasm_F64ReinterpretI64) { TEST(Run_Wasm_F64ReinterpretI64) {
REQUIRE(F64ReinterpretI64); REQUIRE(F64ReinterpretI64);
TestingModule module; TestingModule module;
......
...@@ -420,7 +420,6 @@ TEST(Run_WASM_Int32DivS_trap_effect) { ...@@ -420,7 +420,6 @@ TEST(Run_WASM_Int32DivS_trap_effect) {
CHECK_TRAP(r.Call(0, 0)); CHECK_TRAP(r.Call(0, 0));
} }
void TestFloat32Binop(WasmOpcode opcode, int32_t expected, float a, float b) { void TestFloat32Binop(WasmOpcode opcode, int32_t expected, float a, float b) {
{ {
WasmRunner<int32_t> r; WasmRunner<int32_t> r;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment