[wasm] Introduce special bytecodes for asm.js division/remainder instead of relying on module state.
R=ahaas@chromium.org, bradnelson@chromium.org BUG= Review-Url: https://codereview.chromium.org/1968493002 Cr-Commit-Position: refs/heads/master@{#36148}
This commit is contained in:
parent
ab3f008b8a
commit
067a0d6c61
@ -614,15 +614,20 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
|
|||||||
return BuildF32Max(left, right);
|
return BuildF32Max(left, right);
|
||||||
case wasm::kExprF64Max:
|
case wasm::kExprF64Max:
|
||||||
return BuildF64Max(left, right);
|
return BuildF64Max(left, right);
|
||||||
case wasm::kExprF64Pow: {
|
case wasm::kExprF64Pow:
|
||||||
return BuildF64Pow(left, right);
|
return BuildF64Pow(left, right);
|
||||||
}
|
case wasm::kExprF64Atan2:
|
||||||
case wasm::kExprF64Atan2: {
|
|
||||||
return BuildF64Atan2(left, right);
|
return BuildF64Atan2(left, right);
|
||||||
}
|
case wasm::kExprF64Mod:
|
||||||
case wasm::kExprF64Mod: {
|
|
||||||
return BuildF64Mod(left, right);
|
return BuildF64Mod(left, right);
|
||||||
}
|
case wasm::kExprI32AsmjsDivS:
|
||||||
|
return BuildI32AsmjsDivS(left, right);
|
||||||
|
case wasm::kExprI32AsmjsDivU:
|
||||||
|
return BuildI32AsmjsDivU(left, right);
|
||||||
|
case wasm::kExprI32AsmjsRemS:
|
||||||
|
return BuildI32AsmjsRemS(left, right);
|
||||||
|
case wasm::kExprI32AsmjsRemU:
|
||||||
|
return BuildI32AsmjsRemU(left, right);
|
||||||
default:
|
default:
|
||||||
op = UnsupportedOpcode(opcode);
|
op = UnsupportedOpcode(opcode);
|
||||||
}
|
}
|
||||||
@ -1591,34 +1596,6 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
|
|||||||
Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
|
Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
|
||||||
wasm::WasmCodePosition position) {
|
wasm::WasmCodePosition position) {
|
||||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
if (module_ && module_->asm_js()) {
|
|
||||||
// asm.js semantics return 0 on divide or mod by zero.
|
|
||||||
if (m->Int32DivIsSafe()) {
|
|
||||||
// The hardware instruction does the right thing (e.g. arm).
|
|
||||||
return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check denominator for zero.
|
|
||||||
Diamond z(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
|
|
||||||
// Check numerator for -1. (avoid minint / -1 case).
|
|
||||||
Diamond n(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
|
|
||||||
Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
|
|
||||||
Node* neg =
|
|
||||||
graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
|
|
||||||
|
|
||||||
return n.Phi(MachineRepresentation::kWord32, neg,
|
|
||||||
z.Phi(MachineRepresentation::kWord32,
|
|
||||||
jsgraph()->Int32Constant(0), div));
|
|
||||||
}
|
|
||||||
|
|
||||||
trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
|
trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
|
||||||
Node* before = *control_;
|
Node* before = *control_;
|
||||||
Node* denom_is_m1;
|
Node* denom_is_m1;
|
||||||
@ -1640,26 +1617,6 @@ Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
|
|||||||
Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
|
Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
|
||||||
wasm::WasmCodePosition position) {
|
wasm::WasmCodePosition position) {
|
||||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
if (module_ && module_->asm_js()) {
|
|
||||||
// asm.js semantics return 0 on divide or mod by zero.
|
|
||||||
// Explicit check for x % 0.
|
|
||||||
Diamond z(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
|
|
||||||
// Explicit check for x % -1.
|
|
||||||
Diamond d(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
d.Chain(z.if_false);
|
|
||||||
|
|
||||||
return z.Phi(
|
|
||||||
MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
|
||||||
d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
|
||||||
graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
|
trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
|
||||||
|
|
||||||
@ -1676,23 +1633,6 @@ Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
|
|||||||
Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
|
Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
|
||||||
wasm::WasmCodePosition position) {
|
wasm::WasmCodePosition position) {
|
||||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
if (module_ && module_->asm_js()) {
|
|
||||||
// asm.js semantics return 0 on divide or mod by zero.
|
|
||||||
if (m->Uint32DivIsSafe()) {
|
|
||||||
// The hardware instruction does the right thing (e.g. arm).
|
|
||||||
return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicit check for x % 0.
|
|
||||||
Diamond z(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
|
|
||||||
return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
|
||||||
graph()->NewNode(jsgraph()->machine()->Uint32Div(), left,
|
|
||||||
right, z.if_false));
|
|
||||||
}
|
|
||||||
return graph()->NewNode(
|
return graph()->NewNode(
|
||||||
m->Uint32Div(), left, right,
|
m->Uint32Div(), left, right,
|
||||||
trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
|
trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
|
||||||
@ -1701,25 +1641,96 @@ Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
|
|||||||
Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
|
Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
|
||||||
wasm::WasmCodePosition position) {
|
wasm::WasmCodePosition position) {
|
||||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
if (module_ && module_->asm_js()) {
|
|
||||||
// asm.js semantics return 0 on divide or mod by zero.
|
|
||||||
// Explicit check for x % 0.
|
|
||||||
Diamond z(
|
|
||||||
graph(), jsgraph()->common(),
|
|
||||||
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
|
||||||
BranchHint::kFalse);
|
|
||||||
|
|
||||||
Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
|
|
||||||
z.if_false);
|
|
||||||
return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
|
||||||
rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return graph()->NewNode(
|
return graph()->NewNode(
|
||||||
m->Uint32Mod(), left, right,
|
m->Uint32Mod(), left, right,
|
||||||
trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
|
trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
|
||||||
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
|
// asm.js semantics return 0 on divide or mod by zero.
|
||||||
|
if (m->Int32DivIsSafe()) {
|
||||||
|
// The hardware instruction does the right thing (e.g. arm).
|
||||||
|
return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check denominator for zero.
|
||||||
|
Diamond z(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
|
||||||
|
// Check numerator for -1. (avoid minint / -1 case).
|
||||||
|
Diamond n(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
|
||||||
|
Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
|
||||||
|
Node* neg =
|
||||||
|
graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
|
||||||
|
|
||||||
|
return n.Phi(
|
||||||
|
MachineRepresentation::kWord32, neg,
|
||||||
|
z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0), div));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
|
||||||
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
|
// asm.js semantics return 0 on divide or mod by zero.
|
||||||
|
// Explicit check for x % 0.
|
||||||
|
Diamond z(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
|
||||||
|
// Explicit check for x % -1.
|
||||||
|
Diamond d(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
d.Chain(z.if_false);
|
||||||
|
|
||||||
|
return z.Phi(
|
||||||
|
MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
||||||
|
d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
||||||
|
graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
|
||||||
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
|
// asm.js semantics return 0 on divide or mod by zero.
|
||||||
|
if (m->Uint32DivIsSafe()) {
|
||||||
|
// The hardware instruction does the right thing (e.g. arm).
|
||||||
|
return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit check for x % 0.
|
||||||
|
Diamond z(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
|
||||||
|
return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
||||||
|
graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
|
||||||
|
z.if_false));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
|
||||||
|
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||||
|
// asm.js semantics return 0 on divide or mod by zero.
|
||||||
|
// Explicit check for x % 0.
|
||||||
|
Diamond z(
|
||||||
|
graph(), jsgraph()->common(),
|
||||||
|
graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
|
||||||
|
BranchHint::kFalse);
|
||||||
|
|
||||||
|
Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
|
||||||
|
z.if_false);
|
||||||
|
return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
|
||||||
|
rem);
|
||||||
|
}
|
||||||
|
|
||||||
Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
|
Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
|
||||||
wasm::WasmCodePosition position) {
|
wasm::WasmCodePosition position) {
|
||||||
if (jsgraph()->machine()->Is32()) {
|
if (jsgraph()->machine()->Is32()) {
|
||||||
|
@ -267,6 +267,11 @@ class WasmGraphBuilder {
|
|||||||
Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
|
Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
|
||||||
Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
|
Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
|
||||||
|
|
||||||
|
Node* BuildI32AsmjsDivS(Node* left, Node* right);
|
||||||
|
Node* BuildI32AsmjsRemS(Node* left, Node* right);
|
||||||
|
Node* BuildI32AsmjsDivU(Node* left, Node* right);
|
||||||
|
Node* BuildI32AsmjsRemU(Node* left, Node* right);
|
||||||
|
|
||||||
Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
|
Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
|
||||||
Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
|
Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
|
||||||
Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
|
Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
|
||||||
|
@ -1383,9 +1383,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
|||||||
#ifdef Mul
|
#ifdef Mul
|
||||||
#undef Mul
|
#undef Mul
|
||||||
#endif
|
#endif
|
||||||
#ifdef Div
|
|
||||||
#undef Div
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NON_SIGNED_BINOP(op) \
|
#define NON_SIGNED_BINOP(op) \
|
||||||
static WasmOpcode opcodes[] = { \
|
static WasmOpcode opcodes[] = { \
|
||||||
@ -1464,19 +1461,25 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
|||||||
BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
|
BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
|
||||||
BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
|
BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
|
||||||
BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
|
BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
|
||||||
BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
|
|
||||||
BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
|
||||||
BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
|
||||||
BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
|
||||||
BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
|
||||||
BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
|
||||||
BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
|
BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
|
||||||
|
case Token::DIV: {
|
||||||
|
static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
|
||||||
|
kExprF32Div, kExprF64Div};
|
||||||
|
int type = TypeIndexOf(expr->left(), expr->right(), false);
|
||||||
|
current_function_builder_->Emit(opcodes[type]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Token::MOD: {
|
case Token::MOD: {
|
||||||
TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
|
TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
|
||||||
if (type == kInt32) {
|
if (type == kInt32) {
|
||||||
current_function_builder_->Emit(kExprI32RemS);
|
current_function_builder_->Emit(kExprI32AsmjsRemS);
|
||||||
} else if (type == kUint32) {
|
} else if (type == kUint32) {
|
||||||
current_function_builder_->Emit(kExprI32RemU);
|
current_function_builder_->Emit(kExprI32AsmjsRemU);
|
||||||
} else if (type == kFloat64) {
|
} else if (type == kFloat64) {
|
||||||
current_function_builder_->Emit(kExprF64Mod);
|
current_function_builder_->Emit(kExprF64Mod);
|
||||||
return;
|
return;
|
||||||
|
@ -256,29 +256,30 @@ const WasmCodePosition kNoCodePosition = -1;
|
|||||||
V(F64Log, 0xc7, d_d) \
|
V(F64Log, 0xc7, d_d) \
|
||||||
V(F64Atan2, 0xc8, d_dd) \
|
V(F64Atan2, 0xc8, d_dd) \
|
||||||
V(F64Pow, 0xc9, d_dd) \
|
V(F64Pow, 0xc9, d_dd) \
|
||||||
V(F64Mod, 0xca, d_dd)
|
V(F64Mod, 0xca, d_dd) \
|
||||||
|
V(I32AsmjsDivS, 0xd0, i_ii) \
|
||||||
|
V(I32AsmjsDivU, 0xd1, i_ii) \
|
||||||
|
V(I32AsmjsRemS, 0xd2, i_ii) \
|
||||||
|
V(I32AsmjsRemU, 0xd3, i_ii)
|
||||||
|
|
||||||
// TODO(titzer): sketch of asm-js compatibility bytecodes
|
/* TODO(titzer): introduce compatibility opcodes for these asm.js ops \
|
||||||
/* V(I32AsmjsDivS, 0xd0, i_ii) \ */
|
V(I32AsmjsLoad8S, 0xd4, i_i) \ \
|
||||||
/* V(I32AsmjsDivU, 0xd1, i_ii) \ */
|
V(I32AsmjsLoad8U, 0xd5, i_i) \ \
|
||||||
/* V(I32AsmjsRemS, 0xd2, i_ii) \ */
|
V(I32AsmjsLoad16S, 0xd6, i_i) \ \
|
||||||
/* V(I32AsmjsRemU, 0xd3, i_ii) \ */
|
V(I32AsmjsLoad16U, 0xd7, i_i) \ \
|
||||||
/* V(I32AsmjsLoad8S, 0xd4, i_i) \ */
|
V(I32AsmjsLoad, 0xd8, i_i) \ \
|
||||||
/* V(I32AsmjsLoad8U, 0xd5, i_i) \ */
|
V(F32AsmjsLoad, 0xd9, f_i) \ \
|
||||||
/* V(I32AsmjsLoad16S, 0xd6, i_i) \ */
|
V(F64AsmjsLoad, 0xda, d_i) \ \
|
||||||
/* V(I32AsmjsLoad16U, 0xd7, i_i) \ */
|
V(I32AsmjsStore8, 0xdb, i_i) \ \
|
||||||
/* V(I32AsmjsLoad, 0xd8, i_i) \ */
|
V(I32AsmjsStore16, 0xdc, i_i) \ \
|
||||||
/* V(F32AsmjsLoad, 0xd9, f_i) \ */
|
V(I32AsmjsStore, 0xdd, i_ii) \ \
|
||||||
/* V(F64AsmjsLoad, 0xda, d_i) \ */
|
V(F32AsmjsStore, 0xde, i_if) \ \
|
||||||
/* V(I32AsmjsStore8, 0xdb, i_i) \ */
|
V(F64AsmjsStore, 0xdf, i_id) \ \
|
||||||
/* V(I32AsmjsStore16, 0xdc, i_i) \ */
|
V(I32SAsmjsConvertF32, 0xe0, i_f) \ \
|
||||||
/* V(I32AsmjsStore, 0xdd, i_ii) \ */
|
V(I32UAsmjsConvertF32, 0xe1, i_f) \ \
|
||||||
/* V(F32AsmjsStore, 0xde, i_if) \ */
|
V(I32SAsmjsConvertF64, 0xe2, i_d) \ \
|
||||||
/* V(F64AsmjsStore, 0xdf, i_id) \ */
|
V(I32SAsmjsConvertF64, 0xe3, i_d) \
|
||||||
/* V(I32SAsmjsConvertF32, 0xe0, i_f) \ */
|
*/
|
||||||
/* V(I32UAsmjsConvertF32, 0xe1, i_f) \ */
|
|
||||||
/* V(I32SAsmjsConvertF64, 0xe2, i_d) \ */
|
|
||||||
/* V(I32SAsmjsConvertF64, 0xe3, i_d) */
|
|
||||||
|
|
||||||
// All opcodes.
|
// All opcodes.
|
||||||
#define FOREACH_OPCODE(V) \
|
#define FOREACH_OPCODE(V) \
|
||||||
|
@ -188,6 +188,7 @@
|
|||||||
'trace-extension.cc',
|
'trace-extension.cc',
|
||||||
'wasm/test-run-wasm.cc',
|
'wasm/test-run-wasm.cc',
|
||||||
'wasm/test-run-wasm-64.cc',
|
'wasm/test-run-wasm-64.cc',
|
||||||
|
'wasm/test-run-wasm-asmjs.cc',
|
||||||
'wasm/test-run-wasm-js.cc',
|
'wasm/test-run-wasm-js.cc',
|
||||||
'wasm/test-run-wasm-module.cc',
|
'wasm/test-run-wasm-module.cc',
|
||||||
'wasm/test-signatures.h',
|
'wasm/test-signatures.h',
|
||||||
|
92
test/cctest/wasm/test-run-wasm-asmjs.cc
Normal file
92
test/cctest/wasm/test-run-wasm-asmjs.cc
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "src/base/platform/elapsed-timer.h"
|
||||||
|
|
||||||
|
#include "src/wasm/wasm-macro-gen.h"
|
||||||
|
|
||||||
|
#include "test/cctest/cctest.h"
|
||||||
|
#include "test/cctest/compiler/value-helper.h"
|
||||||
|
#include "test/cctest/wasm/test-signatures.h"
|
||||||
|
#include "test/cctest/wasm/wasm-run-utils.h"
|
||||||
|
|
||||||
|
using namespace v8::base;
|
||||||
|
using namespace v8::internal;
|
||||||
|
using namespace v8::internal::compiler;
|
||||||
|
using namespace v8::internal::wasm;
|
||||||
|
|
||||||
|
// for even shorter tests.
|
||||||
|
#define B2(a, b) kExprBlock, a, b, kExprEnd
|
||||||
|
#define B1(a) kExprBlock, a, kExprEnd
|
||||||
|
#define RET(x) x, kExprReturn, 1
|
||||||
|
#define RET_I8(x) kExprI8Const, x, kExprReturn, 1
|
||||||
|
|
||||||
|
TEST(Run_WASM_Int32AsmjsDivS) {
|
||||||
|
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32());
|
||||||
|
BUILD(r, WASM_BINOP(kExprI32AsmjsDivS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||||
|
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
||||||
|
CHECK_EQ(0, r.Call(0, 100));
|
||||||
|
CHECK_EQ(0, r.Call(100, 0));
|
||||||
|
CHECK_EQ(0, r.Call(-1001, 0));
|
||||||
|
CHECK_EQ(kMin, r.Call(kMin, -1));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Run_WASM_Int32AsmjsRemS) {
|
||||||
|
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32());
|
||||||
|
BUILD(r, WASM_BINOP(kExprI32AsmjsRemS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||||
|
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
||||||
|
CHECK_EQ(33, r.Call(133, 100));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, -1));
|
||||||
|
CHECK_EQ(0, r.Call(100, 0));
|
||||||
|
CHECK_EQ(0, r.Call(-1001, 0));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Run_WASM_Int32AsmjsDivU) {
|
||||||
|
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32());
|
||||||
|
BUILD(r, WASM_BINOP(kExprI32AsmjsDivU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||||
|
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
||||||
|
CHECK_EQ(0, r.Call(0, 100));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, -1));
|
||||||
|
CHECK_EQ(0, r.Call(100, 0));
|
||||||
|
CHECK_EQ(0, r.Call(-1001, 0));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Run_WASM_Int32AsmjsRemU) {
|
||||||
|
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32());
|
||||||
|
BUILD(r, WASM_BINOP(kExprI32AsmjsRemU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||||
|
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
||||||
|
CHECK_EQ(17, r.Call(217, 100));
|
||||||
|
CHECK_EQ(0, r.Call(100, 0));
|
||||||
|
CHECK_EQ(0, r.Call(-1001, 0));
|
||||||
|
CHECK_EQ(0, r.Call(kMin, 0));
|
||||||
|
CHECK_EQ(kMin, r.Call(kMin, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Run_Wasm_LoadMemI32_oob_asm) {
|
||||||
|
TestingModule module;
|
||||||
|
module.origin = kAsmJsOrigin;
|
||||||
|
int32_t* memory = module.AddMemoryElems<int32_t>(8);
|
||||||
|
WasmRunner<int32_t> r(&module, MachineType::Uint32());
|
||||||
|
module.RandomizeMemory(1112);
|
||||||
|
|
||||||
|
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0)));
|
||||||
|
|
||||||
|
memory[0] = 999999;
|
||||||
|
CHECK_EQ(999999, r.Call(0u));
|
||||||
|
// TODO(titzer): offset 29-31 should also be OOB.
|
||||||
|
for (uint32_t offset = 32; offset < 40; offset++) {
|
||||||
|
CHECK_EQ(0, r.Call(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t offset = 0x80000000; offset < 0x80000010; offset++) {
|
||||||
|
CHECK_EQ(0, r.Call(offset));
|
||||||
|
}
|
||||||
|
}
|
@ -409,59 +409,6 @@ TEST(Run_WASM_Int32RemU_trap) {
|
|||||||
CHECK_EQ(kMin, r.Call(kMin, -1));
|
CHECK_EQ(kMin, r.Call(kMin, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Run_WASM_Int32DivS_asmjs) {
|
|
||||||
TestingModule module;
|
|
||||||
module.origin = kAsmJsOrigin;
|
|
||||||
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
|
|
||||||
BUILD(r, WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
|
||||||
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
|
||||||
CHECK_EQ(0, r.Call(0, 100));
|
|
||||||
CHECK_EQ(0, r.Call(100, 0));
|
|
||||||
CHECK_EQ(0, r.Call(-1001, 0));
|
|
||||||
CHECK_EQ(kMin, r.Call(kMin, -1));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Run_WASM_Int32RemS_asmjs) {
|
|
||||||
TestingModule module;
|
|
||||||
module.origin = kAsmJsOrigin;
|
|
||||||
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
|
|
||||||
BUILD(r, WASM_I32_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
|
||||||
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
|
||||||
CHECK_EQ(33, r.Call(133, 100));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, -1));
|
|
||||||
CHECK_EQ(0, r.Call(100, 0));
|
|
||||||
CHECK_EQ(0, r.Call(-1001, 0));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Run_WASM_Int32DivU_asmjs) {
|
|
||||||
TestingModule module;
|
|
||||||
module.origin = kAsmJsOrigin;
|
|
||||||
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
|
|
||||||
BUILD(r, WASM_I32_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
|
||||||
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
|
||||||
CHECK_EQ(0, r.Call(0, 100));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, -1));
|
|
||||||
CHECK_EQ(0, r.Call(100, 0));
|
|
||||||
CHECK_EQ(0, r.Call(-1001, 0));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Run_WASM_Int32RemU_asmjs) {
|
|
||||||
TestingModule module;
|
|
||||||
module.origin = kAsmJsOrigin;
|
|
||||||
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
|
|
||||||
BUILD(r, WASM_I32_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
|
||||||
const int32_t kMin = std::numeric_limits<int32_t>::min();
|
|
||||||
CHECK_EQ(17, r.Call(217, 100));
|
|
||||||
CHECK_EQ(0, r.Call(100, 0));
|
|
||||||
CHECK_EQ(0, r.Call(-1001, 0));
|
|
||||||
CHECK_EQ(0, r.Call(kMin, 0));
|
|
||||||
CHECK_EQ(kMin, r.Call(kMin, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(Run_WASM_Int32DivS_byzero_const) {
|
TEST(Run_WASM_Int32DivS_byzero_const) {
|
||||||
for (int8_t denom = -2; denom < 8; denom++) {
|
for (int8_t denom = -2; denom < 8; denom++) {
|
||||||
WasmRunner<int32_t> r(MachineType::Int32());
|
WasmRunner<int32_t> r(MachineType::Int32());
|
||||||
@ -1403,28 +1350,6 @@ TEST(Run_Wasm_LoadMemI32_oob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(Run_Wasm_LoadMemI32_oob_asm) {
|
|
||||||
TestingModule module;
|
|
||||||
module.origin = kAsmJsOrigin;
|
|
||||||
int32_t* memory = module.AddMemoryElems<int32_t>(8);
|
|
||||||
WasmRunner<int32_t> r(&module, MachineType::Uint32());
|
|
||||||
module.RandomizeMemory(1112);
|
|
||||||
|
|
||||||
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0)));
|
|
||||||
|
|
||||||
memory[0] = 999999;
|
|
||||||
CHECK_EQ(999999, r.Call(0u));
|
|
||||||
// TODO(titzer): offset 29-31 should also be OOB.
|
|
||||||
for (uint32_t offset = 32; offset < 40; offset++) {
|
|
||||||
CHECK_EQ(0, r.Call(offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t offset = 0x80000000; offset < 0x80000010; offset++) {
|
|
||||||
CHECK_EQ(0, r.Call(offset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(Run_Wasm_LoadMem_offset_oob) {
|
TEST(Run_Wasm_LoadMem_offset_oob) {
|
||||||
TestingModule module;
|
TestingModule module;
|
||||||
module.AddMemoryElems<int32_t>(8);
|
module.AddMemoryElems<int32_t>(8);
|
||||||
|
Loading…
Reference in New Issue
Block a user