Commit 0ddddcb8 authored by ahaas's avatar ahaas Committed by Commit bot

[asmjs] Do constant folding for I32Asmjs(Div|Rem)S to avoid checks of constant divisors

This change makes the embenchen/copy benchmark a factor of 2 faster and
brings back the performance loss through graph trimming.

R=titzer@chromium.org
CC=bradnelson@chromium.org

Review-Url: https://codereview.chromium.org/2453343002
Cr-Commit-Position: refs/heads/master@{#40628}
parent 8ba4af44
...@@ -1867,6 +1867,18 @@ Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right, ...@@ -1867,6 +1867,18 @@ Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) { Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
MachineOperatorBuilder* m = jsgraph()->machine(); MachineOperatorBuilder* m = jsgraph()->machine();
Int32Matcher mr(right);
if (mr.HasValue()) {
if (mr.Value() == 0) {
return jsgraph()->Int32Constant(0);
} else if (mr.Value() == -1) {
// The result is the negation of the left input.
return graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
}
return graph()->NewNode(m->Int32Div(), left, right, *control_);
}
// asm.js semantics return 0 on divide or mod by zero. // asm.js semantics return 0 on divide or mod by zero.
if (m->Int32DivIsSafe()) { if (m->Int32DivIsSafe()) {
// The hardware instruction does the right thing (e.g. arm). // The hardware instruction does the right thing (e.g. arm).
...@@ -1896,6 +1908,17 @@ Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) { ...@@ -1896,6 +1908,17 @@ Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) { Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
MachineOperatorBuilder* m = jsgraph()->machine(); MachineOperatorBuilder* m = jsgraph()->machine();
Int32Matcher mr(right);
if (mr.HasValue()) {
if (mr.Value() == 0) {
return jsgraph()->Int32Constant(0);
} else if (mr.Value() == -1) {
return jsgraph()->Int32Constant(0);
}
return graph()->NewNode(m->Int32Mod(), left, right, *control_);
}
// asm.js semantics return 0 on divide or mod by zero. // asm.js semantics return 0 on divide or mod by zero.
// Explicit check for x % 0. // Explicit check for x % 0.
Diamond z( Diamond z(
......
...@@ -494,6 +494,14 @@ class LocalDeclEncoder { ...@@ -494,6 +494,14 @@ class LocalDeclEncoder {
#define WASM_I32_POPCNT(x) x, kExprI32Popcnt #define WASM_I32_POPCNT(x) x, kExprI32Popcnt
#define WASM_I32_EQZ(x) x, kExprI32Eqz #define WASM_I32_EQZ(x) x, kExprI32Eqz
//------------------------------------------------------------------------------
// Asmjs Int32 operations
//------------------------------------------------------------------------------
#define WASM_I32_ASMJS_DIVS(x, y) x, y, kExprI32AsmjsDivS
#define WASM_I32_ASMJS_REMS(x, y) x, y, kExprI32AsmjsRemS
#define WASM_I32_ASMJS_DIVU(x, y) x, y, kExprI32AsmjsDivU
#define WASM_I32_ASMJS_REMU(x, y) x, y, kExprI32AsmjsRemU
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Int64 operations // Int64 operations
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
......
...@@ -448,6 +448,42 @@ WASM_EXEC_TEST(Int32DivS_byzero_const) { ...@@ -448,6 +448,42 @@ WASM_EXEC_TEST(Int32DivS_byzero_const) {
} }
} }
WASM_EXEC_TEST(Int32AsmjsDivS_byzero_const) {
for (int8_t denom = -2; denom < 8; ++denom) {
TestingModule module(execution_mode);
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32());
BUILD(r, WASM_I32_ASMJS_DIVS(WASM_GET_LOCAL(0), WASM_I8(denom)));
FOR_INT32_INPUTS(i) {
if (denom == 0) {
CHECK_EQ(0, r.Call(*i));
} else if (denom == -1 && *i == std::numeric_limits<int32_t>::min()) {
CHECK_EQ(std::numeric_limits<int32_t>::min(), r.Call(*i));
} else {
CHECK_EQ(*i / denom, r.Call(*i));
}
}
}
}
WASM_EXEC_TEST(Int32AsmjsRemS_byzero_const) {
for (int8_t denom = -2; denom < 8; ++denom) {
TestingModule module(execution_mode);
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32());
BUILD(r, WASM_I32_ASMJS_REMS(WASM_GET_LOCAL(0), WASM_I8(denom)));
FOR_INT32_INPUTS(i) {
if (denom == 0) {
CHECK_EQ(0, r.Call(*i));
} else if (denom == -1 && *i == std::numeric_limits<int32_t>::min()) {
CHECK_EQ(0, r.Call(*i));
} else {
CHECK_EQ(*i % denom, r.Call(*i));
}
}
}
}
WASM_EXEC_TEST(Int32DivU_byzero_const) { WASM_EXEC_TEST(Int32DivU_byzero_const) {
for (uint32_t denom = 0xfffffffe; denom < 8; ++denom) { for (uint32_t denom = 0xfffffffe; denom < 8; ++denom) {
WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32()); WasmRunner<uint32_t> r(execution_mode, MachineType::Uint32());
......
...@@ -95,6 +95,8 @@ class TestingModule : public ModuleEnv { ...@@ -95,6 +95,8 @@ class TestingModule : public ModuleEnv {
if (interpreter_) delete interpreter_; if (interpreter_) delete interpreter_;
} }
void ChangeOriginToAsmjs() { origin = kAsmJsOrigin; }
byte* AddMemory(uint32_t size) { byte* AddMemory(uint32_t size) {
CHECK_NULL(instance->mem_start); CHECK_NULL(instance->mem_start);
CHECK_EQ(0, instance->mem_size); CHECK_EQ(0, instance->mem_size);
......
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