Add wasm internal opcodes for asm.js stdlib functions we're missing.

BUG= https://code.google.com/p/v8/issues/detail?id=4203
TEST=mjsunit/asm-wasm
R=aseemgarg@chromium.org,titzer@chromium.org,yangguo@chromium.org
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#34452}
This commit is contained in:
bradnelson 2016-03-02 17:22:01 -08:00 committed by Commit bot
parent f521e7e43e
commit 4db99810da
10 changed files with 409 additions and 90 deletions

View File

@ -1209,6 +1209,104 @@ ExternalReference ExternalReference::f64_nearest_int_wrapper_function(
Redirect(isolate, FUNCTION_ADDR(f64_nearest_int_wrapper))); Redirect(isolate, FUNCTION_ADDR(f64_nearest_int_wrapper)));
} }
static void f64_acos_wrapper(double* param) { *param = std::acos(*param); }
ExternalReference ExternalReference::f64_acos_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_acos_wrapper)));
}
static void f64_asin_wrapper(double* param) { *param = std::asin(*param); }
ExternalReference ExternalReference::f64_asin_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_asin_wrapper)));
}
static void f64_atan_wrapper(double* param) { *param = std::atan(*param); }
ExternalReference ExternalReference::f64_atan_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_atan_wrapper)));
}
static void f64_cos_wrapper(double* param) { *param = std::cos(*param); }
ExternalReference ExternalReference::f64_cos_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_cos_wrapper)));
}
static void f64_sin_wrapper(double* param) { *param = std::sin(*param); }
ExternalReference ExternalReference::f64_sin_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_sin_wrapper)));
}
static void f64_tan_wrapper(double* param) { *param = std::tan(*param); }
ExternalReference ExternalReference::f64_tan_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_tan_wrapper)));
}
static void f64_exp_wrapper(double* param) { *param = std::exp(*param); }
ExternalReference ExternalReference::f64_exp_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_exp_wrapper)));
}
static void f64_log_wrapper(double* param) { *param = std::log(*param); }
ExternalReference ExternalReference::f64_log_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_log_wrapper)));
}
static void f64_pow_wrapper(double* param0, double* param1) {
*param0 = power_double_double(*param0, *param1);
}
ExternalReference ExternalReference::f64_pow_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_pow_wrapper)));
}
static void f64_atan2_wrapper(double* param0, double* param1) {
double x = *param0;
double y = *param1;
// TODO(bradnelson): Find a good place to put this to share
// with the same code in src/runtime/runtime-math.cc
static const double kPiDividedBy4 = 0.78539816339744830962;
if (std::isinf(x) && std::isinf(y)) {
// Make sure that the result in case of two infinite arguments
// is a multiple of Pi / 4. The sign of the result is determined
// by the first argument (x) and the sign of the second argument
// determines the multiplier: one or three.
int multiplier = (x < 0) ? -1 : 1;
if (y < 0) multiplier *= 3;
*param0 = multiplier * kPiDividedBy4;
} else {
*param0 = std::atan2(x, y);
}
}
ExternalReference ExternalReference::f64_atan2_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_atan2_wrapper)));
}
static void f64_mod_wrapper(double* param0, double* param1) {
*param0 = modulo(*param0, *param1);
}
ExternalReference ExternalReference::f64_mod_wrapper_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f64_mod_wrapper)));
}
ExternalReference ExternalReference::log_enter_external_function( ExternalReference ExternalReference::log_enter_external_function(
Isolate* isolate) { Isolate* isolate) {
return ExternalReference( return ExternalReference(

View File

@ -923,6 +923,18 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference f64_ceil_wrapper_function(Isolate* isolate); static ExternalReference f64_ceil_wrapper_function(Isolate* isolate);
static ExternalReference f64_nearest_int_wrapper_function(Isolate* isolate); static ExternalReference f64_nearest_int_wrapper_function(Isolate* isolate);
static ExternalReference f64_acos_wrapper_function(Isolate* isolate);
static ExternalReference f64_asin_wrapper_function(Isolate* isolate);
static ExternalReference f64_atan_wrapper_function(Isolate* isolate);
static ExternalReference f64_cos_wrapper_function(Isolate* isolate);
static ExternalReference f64_sin_wrapper_function(Isolate* isolate);
static ExternalReference f64_tan_wrapper_function(Isolate* isolate);
static ExternalReference f64_exp_wrapper_function(Isolate* isolate);
static ExternalReference f64_log_wrapper_function(Isolate* isolate);
static ExternalReference f64_atan2_wrapper_function(Isolate* isolate);
static ExternalReference f64_pow_wrapper_function(Isolate* isolate);
static ExternalReference f64_mod_wrapper_function(Isolate* isolate);
// Log support. // Log support.
static ExternalReference log_enter_external_function(Isolate* isolate); static ExternalReference log_enter_external_function(Isolate* isolate);
static ExternalReference log_leave_external_function(Isolate* isolate); static ExternalReference log_leave_external_function(Isolate* isolate);

View File

@ -697,6 +697,15 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
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: {
return BuildF64Pow(left, right);
}
case wasm::kExprF64Atan2: {
return BuildF64Atan2(left, right);
}
case wasm::kExprF64Mod: {
return BuildF64Mod(left, right);
}
default: default:
op = UnsupportedOpcode(opcode); op = UnsupportedOpcode(opcode);
} }
@ -824,6 +833,30 @@ Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
op = m->Float64RoundTiesEven().op(); op = m->Float64RoundTiesEven().op();
break; break;
} }
case wasm::kExprF64Acos: {
return BuildF64Acos(input);
}
case wasm::kExprF64Asin: {
return BuildF64Asin(input);
}
case wasm::kExprF64Atan: {
return BuildF64Atan(input);
}
case wasm::kExprF64Cos: {
return BuildF64Cos(input);
}
case wasm::kExprF64Sin: {
return BuildF64Sin(input);
}
case wasm::kExprF64Tan: {
return BuildF64Tan(input);
}
case wasm::kExprF64Exp: {
return BuildF64Exp(input);
}
case wasm::kExprF64Log: {
return BuildF64Log(input);
}
case wasm::kExprI32ConvertI64: case wasm::kExprI32ConvertI64:
op = m->TruncateInt64ToInt32(); op = m->TruncateInt64ToInt32();
break; break;
@ -1418,88 +1451,185 @@ Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
MachineType type = MachineType::Float32(); MachineType type = MachineType::Float32();
ExternalReference ref = ExternalReference ref =
ExternalReference::f32_trunc_wrapper_function(jsgraph()->isolate()); ExternalReference::f32_trunc_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF32Floor(Node* input) { Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
MachineType type = MachineType::Float32(); MachineType type = MachineType::Float32();
ExternalReference ref = ExternalReference ref =
ExternalReference::f32_floor_wrapper_function(jsgraph()->isolate()); ExternalReference::f32_floor_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF32Ceil(Node* input) { Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
MachineType type = MachineType::Float32(); MachineType type = MachineType::Float32();
ExternalReference ref = ExternalReference ref =
ExternalReference::f32_ceil_wrapper_function(jsgraph()->isolate()); ExternalReference::f32_ceil_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) { Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
MachineType type = MachineType::Float32(); MachineType type = MachineType::Float32();
ExternalReference ref = ExternalReference ref =
ExternalReference::f32_nearest_int_wrapper_function(jsgraph()->isolate()); ExternalReference::f32_nearest_int_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF64Trunc(Node* input) { Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
MachineType type = MachineType::Float64(); MachineType type = MachineType::Float64();
ExternalReference ref = ExternalReference ref =
ExternalReference::f64_trunc_wrapper_function(jsgraph()->isolate()); ExternalReference::f64_trunc_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF64Floor(Node* input) { Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
MachineType type = MachineType::Float64(); MachineType type = MachineType::Float64();
ExternalReference ref = ExternalReference ref =
ExternalReference::f64_floor_wrapper_function(jsgraph()->isolate()); ExternalReference::f64_floor_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF64Ceil(Node* input) { Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
MachineType type = MachineType::Float64(); MachineType type = MachineType::Float64();
ExternalReference ref = ExternalReference ref =
ExternalReference::f64_ceil_wrapper_function(jsgraph()->isolate()); ExternalReference::f64_ceil_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) { Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
MachineType type = MachineType::Float64(); MachineType type = MachineType::Float64();
ExternalReference ref = ExternalReference ref =
ExternalReference::f64_nearest_int_wrapper_function(jsgraph()->isolate()); ExternalReference::f64_nearest_int_wrapper_function(jsgraph()->isolate());
return BuildRoundingInstruction(input, ref, type); return BuildCFuncInstruction(ref, type, input);
} }
Node* WasmGraphBuilder::BuildRoundingInstruction(Node* input, Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
ExternalReference ref, MachineType type = MachineType::Float64();
MachineType type) { ExternalReference ref =
// We do truncation by calling a C function which calculates the truncation ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
// for us. The input is passed to the C function as a double* to avoid double return BuildCFuncInstruction(ref, type, input);
// parameters. For this we reserve a slot on the stack, store the parameter in }
// that slot, pass a pointer to the slot to the C function, and after calling
// the C function we collect the return value from the stack slot.
Node* stack_slot_param = Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Atan(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_atan_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Cos(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_cos_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Sin(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_sin_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Tan(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_tan_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Exp(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_exp_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Log(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_log_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Atan2(Node* left, Node* right) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_atan2_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, left, right);
}
Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_pow_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, left, right);
}
Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
MachineType type = MachineType::Float64();
ExternalReference ref =
ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
return BuildCFuncInstruction(ref, type, left, right);
}
Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
MachineType type, Node* input0,
Node* input1) {
// We do truncation by calling a C function which calculates the result.
// The input is passed to the C function as a double*'s to avoid double
// parameters. For this we reserve slots on the stack, store the parameters
// in those slots, pass pointers to the slot to the C function,
// and after calling the C function we collect the return value from
// the stack slot.
Node* stack_slot_param0 =
graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation())); graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
const Operator* store_op = jsgraph()->machine()->Store( const Operator* store_op0 = jsgraph()->machine()->Store(
StoreRepresentation(type.representation(), kNoWriteBarrier)); StoreRepresentation(type.representation(), kNoWriteBarrier));
*effect_ = *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0), jsgraph()->Int32Constant(0), input0, *effect_,
input, *effect_, *control_); *control_);
Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, 1);
sig_builder.AddParam(MachineType::Pointer());
Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
Node** args = Buffer(4);
args[0] = function;
args[1] = stack_slot_param0;
int input_count = 1;
Node* args[] = {function, stack_slot_param}; if (input1 != nullptr) {
Node* stack_slot_param1 = graph()->NewNode(
jsgraph()->machine()->StackSlot(type.representation()));
const Operator* store_op1 = jsgraph()->machine()->Store(
StoreRepresentation(type.representation(), kNoWriteBarrier));
*effect_ = graph()->NewNode(store_op1, stack_slot_param1,
jsgraph()->Int32Constant(0), input1, *effect_,
*control_);
args = Realloc(args, 5);
args[2] = stack_slot_param1;
++input_count;
}
Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
input_count);
sig_builder.AddParam(MachineType::Pointer());
if (input1 != nullptr) {
sig_builder.AddParam(MachineType::Pointer());
}
BuildCCall(sig_builder.Build(), args); BuildCCall(sig_builder.Build(), args);
const Operator* load_op = jsgraph()->machine()->Load(type); const Operator* load_op = jsgraph()->machine()->Load(type);
Node* load = Node* load =
graph()->NewNode(load_op, stack_slot_param, jsgraph()->Int32Constant(0), graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
*effect_, *control_); *effect_, *control_);
*effect_ = load; *effect_ = load;
return load; return load;
@ -1547,7 +1677,6 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
return call; return call;
} }
Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) { Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
DCHECK_NULL(args[0]); DCHECK_NULL(args[0]);

View File

@ -180,8 +180,8 @@ class WasmGraphBuilder {
Node* BuildI32Popcnt(Node* input); Node* BuildI32Popcnt(Node* input);
Node* BuildI64Ctz(Node* input); Node* BuildI64Ctz(Node* input);
Node* BuildI64Popcnt(Node* input); Node* BuildI64Popcnt(Node* input);
Node* BuildRoundingInstruction(Node* input, ExternalReference ref, Node* BuildCFuncInstruction(ExternalReference ref, MachineType type,
MachineType type); Node* input0, Node* input1 = nullptr);
Node* BuildF32Trunc(Node* input); Node* BuildF32Trunc(Node* input);
Node* BuildF32Floor(Node* input); Node* BuildF32Floor(Node* input);
Node* BuildF32Ceil(Node* input); Node* BuildF32Ceil(Node* input);
@ -191,6 +191,18 @@ class WasmGraphBuilder {
Node* BuildF64Ceil(Node* input); Node* BuildF64Ceil(Node* input);
Node* BuildF64NearestInt(Node* input); Node* BuildF64NearestInt(Node* input);
Node* BuildF64Acos(Node* input);
Node* BuildF64Asin(Node* input);
Node* BuildF64Atan(Node* input);
Node* BuildF64Cos(Node* input);
Node* BuildF64Sin(Node* input);
Node* BuildF64Tan(Node* input);
Node* BuildF64Exp(Node* input);
Node* BuildF64Log(Node* input);
Node* BuildF64Pow(Node* left, Node* right);
Node* BuildF64Atan2(Node* left, Node* right);
Node* BuildF64Mod(Node* left, Node* right);
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*));

View File

@ -115,6 +115,30 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
"f64_ceil_wrapper"); "f64_ceil_wrapper");
Add(ExternalReference::f64_nearest_int_wrapper_function(isolate).address(), Add(ExternalReference::f64_nearest_int_wrapper_function(isolate).address(),
"f64_nearest_int_wrapper"); "f64_nearest_int_wrapper");
Add(ExternalReference::f64_acos_wrapper_function(isolate).address(),
"f64_acos_wrapper");
Add(ExternalReference::f64_asin_wrapper_function(isolate).address(),
"f64_asin_wrapper");
Add(ExternalReference::f64_atan_wrapper_function(isolate).address(),
"f64_atan_wrapper");
Add(ExternalReference::f64_cos_wrapper_function(isolate).address(),
"f64_cos_wrapper");
Add(ExternalReference::f64_sin_wrapper_function(isolate).address(),
"f64_sin_wrapper");
Add(ExternalReference::f64_tan_wrapper_function(isolate).address(),
"f64_tan_wrapper");
Add(ExternalReference::f64_exp_wrapper_function(isolate).address(),
"f64_exp_wrapper");
Add(ExternalReference::f64_log_wrapper_function(isolate).address(),
"f64_log_wrapper");
Add(ExternalReference::f64_pow_wrapper_function(isolate).address(),
"f64_pow_wrapper");
Add(ExternalReference::f64_atan2_wrapper_function(isolate).address(),
"f64_atan2_wrapper");
Add(ExternalReference::f64_mod_wrapper_function(isolate).address(),
"f64_mod_wrapper");
Add(ExternalReference::log_enter_external_function(isolate).address(), Add(ExternalReference::log_enter_external_function(isolate).address(),
"Logger::EnterExternal"); "Logger::EnterExternal");
Add(ExternalReference::log_leave_external_function(isolate).address(), Add(ExternalReference::log_leave_external_function(isolate).address(),

View File

@ -846,36 +846,44 @@ class AsmWasmBuilderImpl : public AstVisitor {
return false; return false;
} }
case AsmTyper::kMathAcos: { case AsmTyper::kMathAcos: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Acos);
break;
} }
case AsmTyper::kMathAsin: { case AsmTyper::kMathAsin: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Asin);
break;
} }
case AsmTyper::kMathAtan: { case AsmTyper::kMathAtan: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Atan);
break;
} }
case AsmTyper::kMathCos: { case AsmTyper::kMathCos: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Cos);
break;
} }
case AsmTyper::kMathSin: { case AsmTyper::kMathSin: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Sin);
break;
} }
case AsmTyper::kMathTan: { case AsmTyper::kMathTan: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Tan);
break;
} }
case AsmTyper::kMathExp: { case AsmTyper::kMathExp: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Exp);
break;
} }
case AsmTyper::kMathLog: { case AsmTyper::kMathLog: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Log);
break;
} }
case AsmTyper::kMathCeil: { case AsmTyper::kMathCeil: {
if (call_type == kAstF32) { if (call_type == kAstF32) {
@ -908,8 +916,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
break; break;
} }
case AsmTyper::kMathAbs: { case AsmTyper::kMathAbs: {
// TODO(bradnelson): Handle signed. // TODO(bradnelson): Should this be cast to float?
if (call_type == kAstF32) { if (call_type == kAstI32) {
current_function_builder_->Emit(kExprIfElse);
current_function_builder_->Emit(kExprI32LtS);
Visit(args->at(0));
byte code[] = {WASM_I8(0)};
current_function_builder_->EmitCode(code, sizeof(code));
current_function_builder_->Emit(kExprI32Sub);
current_function_builder_->EmitCode(code, sizeof(code));
Visit(args->at(0));
} else if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Abs); current_function_builder_->Emit(kExprF32Abs);
} else if (call_type == kAstF64) { } else if (call_type == kAstF64) {
current_function_builder_->Emit(kExprF64Abs); current_function_builder_->Emit(kExprF64Abs);
@ -919,9 +936,13 @@ class AsmWasmBuilderImpl : public AstVisitor {
break; break;
} }
case AsmTyper::kMathMin: { case AsmTyper::kMathMin: {
// TODO(bradnelson): Handle signed.
// TODO(bradnelson): Change wasm to match Math.min in asm.js mode. // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
if (call_type == kAstF32) { if (call_type == kAstI32) {
current_function_builder_->Emit(kExprIfElse);
current_function_builder_->Emit(kExprI32LeS);
Visit(args->at(0));
Visit(args->at(1));
} else if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Min); current_function_builder_->Emit(kExprF32Min);
} else if (call_type == kAstF64) { } else if (call_type == kAstF64) {
current_function_builder_->Emit(kExprF64Min); current_function_builder_->Emit(kExprF64Min);
@ -931,9 +952,13 @@ class AsmWasmBuilderImpl : public AstVisitor {
break; break;
} }
case AsmTyper::kMathMax: { case AsmTyper::kMathMax: {
// TODO(bradnelson): Handle signed.
// TODO(bradnelson): Change wasm to match Math.max in asm.js mode. // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
if (call_type == kAstF32) { if (call_type == kAstI32) {
current_function_builder_->Emit(kExprIfElse);
current_function_builder_->Emit(kExprI32GtS);
Visit(args->at(0));
Visit(args->at(1));
} else if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Max); current_function_builder_->Emit(kExprF32Max);
} else if (call_type == kAstF64) { } else if (call_type == kAstF64) {
current_function_builder_->Emit(kExprF64Max); current_function_builder_->Emit(kExprF64Max);
@ -943,12 +968,14 @@ class AsmWasmBuilderImpl : public AstVisitor {
break; break;
} }
case AsmTyper::kMathAtan2: { case AsmTyper::kMathAtan2: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Atan2);
break;
} }
case AsmTyper::kMathPow: { case AsmTyper::kMathPow: {
UNREACHABLE(); DCHECK_EQ(kAstF64, call_type);
break; // TODO(bradnelson): Implement as external. current_function_builder_->Emit(kExprF64Pow);
break;
} }
case AsmTyper::kMathImul: { case AsmTyper::kMathImul: {
current_function_builder_->Emit(kExprI32Mul); current_function_builder_->Emit(kExprI32Mul);
@ -1243,7 +1270,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
} else if (type == kUint32) { } else if (type == kUint32) {
current_function_builder_->Emit(kExprI32RemU); current_function_builder_->Emit(kExprI32RemU);
} else if (type == kFloat64) { } else if (type == kFloat64) {
ModF64(expr); current_function_builder_->Emit(kExprF64Mod);
return; return;
} else { } else {
UNREACHABLE(); UNREACHABLE();
@ -1262,32 +1289,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
} }
void ModF64(BinaryOperation* expr) {
current_function_builder_->EmitWithU8(kExprBlock, 3);
uint16_t index_0 = current_function_builder_->AddLocal(kAstF64);
uint16_t index_1 = current_function_builder_->AddLocal(kAstF64);
current_function_builder_->Emit(kExprSetLocal);
AddLeb128(index_0, true);
RECURSE(Visit(expr->left()));
current_function_builder_->Emit(kExprSetLocal);
AddLeb128(index_1, true);
RECURSE(Visit(expr->right()));
current_function_builder_->Emit(kExprF64Sub);
current_function_builder_->Emit(kExprGetLocal);
AddLeb128(index_0, true);
current_function_builder_->Emit(kExprF64Mul);
current_function_builder_->Emit(kExprGetLocal);
AddLeb128(index_1, true);
// Use trunc instead of two casts
current_function_builder_->Emit(kExprF64SConvertI32);
current_function_builder_->Emit(kExprI32SConvertF64);
current_function_builder_->Emit(kExprF64Div);
current_function_builder_->Emit(kExprGetLocal);
AddLeb128(index_0, true);
current_function_builder_->Emit(kExprGetLocal);
AddLeb128(index_1, true);
}
void AddLeb128(uint32_t index, bool is_local) { void AddLeb128(uint32_t index, bool is_local) {
std::vector<uint8_t> index_vec = UnsignedLEB128From(index); std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
if (is_local) { if (is_local) {

View File

@ -293,6 +293,7 @@ class WasmDecoder : public Decoder {
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE #undef DECLARE_OPCODE_CASE
} }
UNREACHABLE(); UNREACHABLE();

View File

@ -66,6 +66,7 @@ static void InitSigTable() {
#define SET_SIG_TABLE(name, opcode, sig) \ #define SET_SIG_TABLE(name, opcode, sig) \
kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1; kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE); FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
FOREACH_ASMJS_COMPAT_OPCODE(SET_SIG_TABLE);
#undef SET_SIG_TABLE #undef SET_SIG_TABLE
} }

View File

@ -254,6 +254,20 @@ std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
V(I32ReinterpretF32, 0xb4, i_f) \ V(I32ReinterpretF32, 0xb4, i_f) \
V(I64ReinterpretF64, 0xb5, l_d) V(I64ReinterpretF64, 0xb5, l_d)
// For compatibility with Asm.js.
#define FOREACH_ASMJS_COMPAT_OPCODE(V) \
V(F64Acos, 0xc0, d_d) \
V(F64Asin, 0xc1, d_d) \
V(F64Atan, 0xc2, d_d) \
V(F64Cos, 0xc3, d_d) \
V(F64Sin, 0xc4, d_d) \
V(F64Tan, 0xc5, d_d) \
V(F64Exp, 0xc6, d_d) \
V(F64Log, 0xc7, d_d) \
V(F64Atan2, 0xc8, d_dd) \
V(F64Pow, 0xc9, d_dd) \
V(F64Mod, 0xca, d_dd)
// All opcodes. // All opcodes.
#define FOREACH_OPCODE(V) \ #define FOREACH_OPCODE(V) \
FOREACH_CONTROL_OPCODE(V) \ FOREACH_CONTROL_OPCODE(V) \
@ -261,7 +275,8 @@ std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
FOREACH_SIMPLE_OPCODE(V) \ FOREACH_SIMPLE_OPCODE(V) \
FOREACH_STORE_MEM_OPCODE(V) \ FOREACH_STORE_MEM_OPCODE(V) \
FOREACH_LOAD_MEM_OPCODE(V) \ FOREACH_LOAD_MEM_OPCODE(V) \
FOREACH_MISC_MEM_OPCODE(V) FOREACH_MISC_MEM_OPCODE(V) \
FOREACH_ASMJS_COMPAT_OPCODE(V)
// All signatures. // All signatures.
#define FOREACH_SIGNATURE(V) \ #define FOREACH_SIGNATURE(V) \

View File

@ -1301,6 +1301,13 @@ TestForeignVariables();
function Module(stdlib) { function Module(stdlib) {
"use asm"; "use asm";
var StdlibMathCeil = stdlib.Math.ceil;
var StdlibMathFloor = stdlib.Math.floor;
var StdlibMathSqrt = stdlib.Math.sqrt;
var StdlibMathAbs = stdlib.Math.abs;
var StdlibMathMin = stdlib.Math.min;
var StdlibMathMax = stdlib.Math.max;
var StdlibMathAcos = stdlib.Math.acos; var StdlibMathAcos = stdlib.Math.acos;
var StdlibMathAsin = stdlib.Math.asin; var StdlibMathAsin = stdlib.Math.asin;
var StdlibMathAtan = stdlib.Math.atan; var StdlibMathAtan = stdlib.Math.atan;
@ -1309,20 +1316,26 @@ TestForeignVariables();
var StdlibMathTan = stdlib.Math.tan; var StdlibMathTan = stdlib.Math.tan;
var StdlibMathExp = stdlib.Math.exp; var StdlibMathExp = stdlib.Math.exp;
var StdlibMathLog = stdlib.Math.log; var StdlibMathLog = stdlib.Math.log;
var StdlibMathCeil = stdlib.Math.ceil;
var StdlibMathFloor = stdlib.Math.floor;
var StdlibMathSqrt = stdlib.Math.sqrt;
var StdlibMathAbs = stdlib.Math.abs;
var StdlibMathMin = stdlib.Math.min;
var StdlibMathMax = stdlib.Math.max;
var StdlibMathAtan2 = stdlib.Math.atan2; var StdlibMathAtan2 = stdlib.Math.atan2;
var StdlibMathPow = stdlib.Math.pow; var StdlibMathPow = stdlib.Math.pow;
var StdlibMathImul = stdlib.Math.imul; var StdlibMathImul = stdlib.Math.imul;
var fround = stdlib.Math.fround; var fround = stdlib.Math.fround;
function deltaEqual(x, y) {
x = +x;
y = +y;
var t = 0.0;
t = x - y;
if (t < 0.0) {
t = t * -1.0;
}
return (t < 1.0e-13) | 0;
}
function caller() { function caller() {
// TODO(bradnelson): Test transendentals when implemented. if (!deltaEqual(StdlibMathSqrt(123.0), 11.090536506409418)) return 0;
if (StdlibMathSqrt(123.0) != 11.090536506409418) return 0;
if (StdlibMathSqrt(fround(256.0)) != fround(16.0)) return 0; if (StdlibMathSqrt(fround(256.0)) != fround(16.0)) return 0;
if (StdlibMathCeil(123.7) != 124.0) return 0; if (StdlibMathCeil(123.7) != 124.0) return 0;
if (StdlibMathCeil(fround(123.7)) != fround(124.0)) return 0; if (StdlibMathCeil(fround(123.7)) != fround(124.0)) return 0;
@ -1336,7 +1349,20 @@ TestForeignVariables();
if (StdlibMathMax(123.4, 1236.4) != 1236.4) return 0; if (StdlibMathMax(123.4, 1236.4) != 1236.4) return 0;
if (StdlibMathMax(fround(123.4), fround(1236.4)) if (StdlibMathMax(fround(123.4), fround(1236.4))
!= fround(1236.4)) return 0; != fround(1236.4)) return 0;
if (!deltaEqual(StdlibMathAcos(0.1), 1.4706289056333368)) return 0;
if (!deltaEqual(StdlibMathAsin(0.2), 0.2013579207903308)) return 0;
if (!deltaEqual(StdlibMathAtan(0.2), 0.19739555984988078)) return 0;
if (!deltaEqual(StdlibMathCos(0.2), 0.9800665778412416)) return 0;
if (!deltaEqual(StdlibMathSin(0.2), 0.19866933079506122)) return 0;
if (!deltaEqual(StdlibMathTan(0.2), 0.20271003550867250)) return 0;
if (!deltaEqual(StdlibMathExp(0.2), 1.2214027581601699)) return 0;
if (!deltaEqual(StdlibMathLog(0.2), -1.6094379124341003)) return 0;
if (StdlibMathImul(6, 7) != 42) return 0; if (StdlibMathImul(6, 7) != 42) return 0;
if (!deltaEqual(StdlibMathAtan2(6.0, 7.0), 0.7086262721276703)) return 0;
if (StdlibMathPow(6.0, 7.0) != 279936.0) return 0;
return 1; return 1;
} }