Commit 6c2bb838 authored by epertoso's avatar epertoso Committed by Commit bot

[stubs] Introduce MultiplyStub.

Adds a MultiplyStub for the multiplication operator and hooks it with TurboFan and Ignition.

Currently, the SMI times SMI case is handled by converting both the operands to double precision floating points, we may consider adding a fast path later.

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

Cr-Commit-Position: refs/heads/master@{#35287}
parent e00a0c62
......@@ -224,6 +224,12 @@ Callable CodeFactory::Subtract(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::Multiply(Isolate* isolate) {
MultiplyStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::BitwiseAnd(Isolate* isolate) {
BitwiseAndStub stub(isolate);
......
......@@ -84,6 +84,7 @@ class CodeFactory final {
static Callable Add(Isolate* isolate);
static Callable Subtract(Isolate* isolate);
static Callable Multiply(Isolate* isolate);
static Callable BitwiseAnd(Isolate* isolate);
static Callable BitwiseOr(Isolate* isolate);
static Callable BitwiseXor(Isolate* isolate);
......
......@@ -1031,6 +1031,153 @@ void SubtractStub::GenerateAssembly(
}
}
void MultiplyStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
using compiler::Node;
typedef compiler::CodeStubAssembler::Label Label;
typedef compiler::CodeStubAssembler::Variable Variable;
Node* context = assembler->Parameter(2);
// Shared entry point for floating point multiplication.
Label do_fmul(assembler);
Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64),
var_rhs_float64(assembler, MachineRepresentation::kFloat64);
Node* number_map = assembler->HeapNumberMapConstant();
// We might need to loop one or two times due to ToNumber conversions.
Variable var_lhs(assembler, MachineRepresentation::kTagged),
var_rhs(assembler, MachineRepresentation::kTagged);
Variable* loop_variables[] = {&var_lhs, &var_rhs};
Label loop(assembler, 2, loop_variables);
var_lhs.Bind(assembler->Parameter(0));
var_rhs.Bind(assembler->Parameter(1));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
Node* lhs = var_lhs.value();
Node* rhs = var_rhs.value();
Label lhs_is_smi(assembler), lhs_is_not_smi(assembler);
assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
assembler->Bind(&lhs_is_smi);
{
Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
&rhs_is_not_smi);
assembler->Bind(&rhs_is_smi);
{
// Both {lhs} and {rhs} are Smis. Convert them to double and multiply.
// TODO(epertoso): use SmiMulWithOverflow once available.
var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
assembler->Goto(&do_fmul);
}
assembler->Bind(&rhs_is_not_smi);
{
Node* rhs_map = assembler->LoadMap(rhs);
// Check if {rhs} is a HeapNumber.
Label rhs_is_number(assembler),
rhs_is_not_number(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
&rhs_is_number, &rhs_is_not_number);
assembler->Bind(&rhs_is_number);
{
// Convert {lhs} to a double and multiply it with the value of {rhs}.
var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
assembler->Goto(&do_fmul);
}
assembler->Bind(&rhs_is_not_number);
{
// Multiplication is commutative, swap {lhs} with {rhs} and loop.
var_lhs.Bind(rhs);
var_rhs.Bind(lhs);
assembler->Goto(&loop);
}
}
}
assembler->Bind(&lhs_is_not_smi);
{
Node* lhs_map = assembler->LoadMap(lhs);
// Check if {lhs} is a HeapNumber.
Label lhs_is_number(assembler),
lhs_is_not_number(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(lhs_map, number_map),
&lhs_is_number, &lhs_is_not_number);
assembler->Bind(&lhs_is_number);
{
// Check if {rhs} is a Smi.
Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
&rhs_is_not_smi);
assembler->Bind(&rhs_is_smi);
{
// Convert {rhs} to a double and multiply it with the value of {lhs}.
var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
assembler->Goto(&do_fmul);
}
assembler->Bind(&rhs_is_not_smi);
{
Node* rhs_map = assembler->LoadMap(rhs);
// Check if {rhs} is a HeapNumber.
Label rhs_is_number(assembler),
rhs_is_not_number(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
&rhs_is_number, &rhs_is_not_number);
assembler->Bind(&rhs_is_number);
{
// Both {lhs} and {rhs} are HeapNumbers. Load their values and
// multiply them.
var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
assembler->Goto(&do_fmul);
}
assembler->Bind(&rhs_is_not_number);
{
// Multiplication is commutative, swap {lhs} with {rhs} and loop.
var_lhs.Bind(rhs);
var_rhs.Bind(lhs);
assembler->Goto(&loop);
}
}
}
assembler->Bind(&lhs_is_not_number);
{
// Convert {lhs} to a Number and loop.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
assembler->Goto(&loop);
}
}
}
assembler->Bind(&do_fmul);
{
Node* value =
assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
Node* result = assembler->ChangeFloat64ToTagged(value);
assembler->Return(result);
}
}
void BitwiseAndStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
using compiler::Node;
......
......@@ -112,6 +112,7 @@ namespace internal {
V(StringLength) \
V(Add) \
V(Subtract) \
V(Multiply) \
V(BitwiseAnd) \
V(BitwiseOr) \
V(BitwiseXor) \
......@@ -689,6 +690,14 @@ class SubtractStub final : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(Subtract, TurboFanCodeStub);
};
class MultiplyStub final : public TurboFanCodeStub {
public:
explicit MultiplyStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
DEFINE_TURBOFAN_CODE_STUB(Multiply, TurboFanCodeStub);
};
class BitwiseAndStub final : public TurboFanCodeStub {
public:
explicit BitwiseAndStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
......
......@@ -65,6 +65,7 @@ class Schedule;
CODE_STUB_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
V(Float64Add) \
V(Float64Sub) \
V(Float64Mul) \
V(Float64InsertLowWord32) \
V(Float64InsertHighWord32) \
V(IntPtrAdd) \
......
......@@ -73,7 +73,6 @@ Reduction JSGenericLowering::Reduce(Node* node) {
REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
#undef REPLACE_BINARY_OP_IC_CALL
......@@ -95,6 +94,7 @@ REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
}
REPLACE_STUB_CALL(Add)
REPLACE_STUB_CALL(Subtract)
REPLACE_STUB_CALL(Multiply)
REPLACE_STUB_CALL(BitwiseAnd)
REPLACE_STUB_CALL(BitwiseOr)
REPLACE_STUB_CALL(BitwiseXor)
......
......@@ -661,7 +661,7 @@ void Interpreter::DoSub(InterpreterAssembler* assembler) {
//
// Multiply accumulator by register <src>.
void Interpreter::DoMul(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kMultiply, assembler);
DoBinaryOp(CodeFactory::Multiply(isolate_), assembler);
}
......
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