Commit 1abd7897 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce proper abstractions for ToNumber truncations.

Introduce TruncateTaggedToFloat64 and TruncateTaggedToWord32 into the
CodeStubAssembler, which encapsulates the ToNumber truncation and
returns the resulting number as either Float64 or further truncated to
Word32.

R=jarin@chromium.org
BUG=v8:4587
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#35051}
parent 373cf6b2
......@@ -2033,74 +2033,14 @@ BUILTIN(MathImul) {
// ES6 section 20.2.2.32 Math.sqrt ( x )
void Builtins::Generate_MathSqrt(compiler::CodeStubAssembler* assembler) {
typedef compiler::CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef compiler::CodeStubAssembler::Variable Variable;
using compiler::Node;
Node* x = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
// Shared entry for the floating point sqrt.
Label do_fsqrt(assembler);
Variable var_fsqrt_x(assembler, MachineRepresentation::kFloat64);
// We might need to loop once due to the ToNumber conversion.
Variable var_x(assembler, MachineRepresentation::kTagged);
Label loop(assembler, &var_x);
var_x.Bind(assembler->Parameter(1));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(assembler), if_xisnotsmi(assembler);
assembler->Branch(assembler->WordIsSmi(x), &if_xissmi, &if_xisnotsmi);
assembler->Bind(&if_xissmi);
{
// Perform the floating point sqrt.
var_fsqrt_x.Bind(assembler->SmiToFloat64(x));
assembler->Goto(&do_fsqrt);
}
assembler->Bind(&if_xisnotsmi);
{
// Load the map of {x}.
Node* x_map = assembler->LoadMap(x);
// Check if {x} is a HeapNumber.
Label if_xisnumber(assembler),
if_xisnotnumber(assembler, Label::kDeferred);
assembler->Branch(
assembler->WordEqual(x_map, assembler->HeapNumberMapConstant()),
&if_xisnumber, &if_xisnotnumber);
assembler->Bind(&if_xisnumber);
{
// Perform the floating point sqrt.
var_fsqrt_x.Bind(assembler->LoadHeapNumberValue(x));
assembler->Goto(&do_fsqrt);
}
assembler->Bind(&if_xisnotnumber);
{
// Convert {x} to a Number first.
Callable callable =
CodeFactory::NonNumberToNumber(assembler->isolate());
var_x.Bind(assembler->CallStub(callable, context, x));
assembler->Goto(&loop);
}
}
}
assembler->Bind(&do_fsqrt);
{
Node* x = var_fsqrt_x.value();
Node* value = assembler->Float64Sqrt(x);
Node* result = assembler->AllocateHeapNumberWithValue(value);
assembler->Return(result);
}
Node* x_value = assembler->TruncateTaggedToFloat64(context, x);
Node* value = assembler->Float64Sqrt(x_value);
Node* result = assembler->AllocateHeapNumberWithValue(value);
assembler->Return(result);
}
// -----------------------------------------------------------------------------
......
......@@ -1033,180 +1033,46 @@ void SubtractStub::GenerateAssembly(
}
}
namespace {
void GenerateBitwiseOperation(
compiler::CodeStubAssembler* assembler,
compiler::Node* (compiler::CodeStubAssembler::*bitop)(compiler::Node*,
compiler::Node*)) {
typedef compiler::CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef compiler::CodeStubAssembler::Variable Variable;
Node* context = assembler->Parameter(2);
// Shared entry for word32 bitwise operation.
Label do_bitop(assembler);
Variable var_bitop_lhs(assembler, MachineRepresentation::kWord32),
var_bitop_rhs(assembler, MachineRepresentation::kWord32);
// We might need to loop several times due to ToNumber conversions.
Variable var_lhs(assembler, MachineRepresentation::kTagged),
var_rhs(assembler, MachineRepresentation::kTagged);
Variable* loop_vars[2] = {&var_lhs, &var_rhs};
Label loop(assembler, 2, loop_vars);
var_lhs.Bind(assembler->Parameter(0));
var_rhs.Bind(assembler->Parameter(1));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Load the current {lhs} and {rhs} values.
Node* lhs = var_lhs.value();
Node* rhs = var_rhs.value();
// Check if the {lhs} is a Smi or a HeapObject.
Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
assembler->Bind(&if_lhsissmi);
{
// Check if the {rhs} is also a Smi.
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
&if_rhsisnotsmi);
assembler->Bind(&if_rhsissmi);
{
// Perform the word32 bitwise operation.
var_bitop_lhs.Bind(assembler->SmiToInt32(lhs));
var_bitop_rhs.Bind(assembler->SmiToInt32(rhs));
assembler->Goto(&do_bitop);
}
assembler->Bind(&if_rhsisnotsmi);
{
// Load the map of the {rhs}.
Node* rhs_map = assembler->LoadMap(rhs);
// Check if {rhs} is a HeapNumber.
Label if_rhsisnumber(assembler),
if_rhsisnotnumber(assembler, Label::kDeferred);
Node* number_map = assembler->HeapNumberMapConstant();
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
&if_rhsisnumber, &if_rhsisnotnumber);
assembler->Bind(&if_rhsisnumber);
{
// Perform the word32 bitwise operation.
var_bitop_lhs.Bind(assembler->SmiToInt32(lhs));
var_bitop_rhs.Bind(assembler->TruncateHeapNumberValueToInt32(rhs));
assembler->Goto(&do_bitop);
}
assembler->Bind(&if_rhsisnotnumber);
{
// Convert the {rhs} to a Number first.
Callable callable =
CodeFactory::NonNumberToNumber(assembler->isolate());
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
assembler->Goto(&loop);
}
}
}
assembler->Bind(&if_lhsisnotsmi);
{
// Load the map of the {lhs}.
Node* lhs_map = assembler->LoadMap(lhs);
// Check if the {lhs} is a HeapNumber.
Label if_lhsisnumber(assembler),
if_lhsisnotnumber(assembler, Label::kDeferred);
Node* number_map = assembler->HeapNumberMapConstant();
assembler->Branch(assembler->WordEqual(lhs_map, number_map),
&if_lhsisnumber, &if_lhsisnotnumber);
assembler->Bind(&if_lhsisnumber);
{
// Check if the {rhs} is a Smi.
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
&if_rhsisnotsmi);
assembler->Bind(&if_rhsissmi);
{
// Perform the word32 bitwise operation.
var_bitop_lhs.Bind(assembler->TruncateHeapNumberValueToInt32(lhs));
var_bitop_rhs.Bind(assembler->SmiToInt32(rhs));
assembler->Goto(&do_bitop);
}
assembler->Bind(&if_rhsisnotsmi);
{
// Load the map of the {rhs}.
Node* rhs_map = assembler->LoadMap(rhs);
// Check if the {rhs} is a HeapNumber.
Label if_rhsisnumber(assembler),
if_rhsisnotnumber(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
&if_rhsisnumber, &if_rhsisnotnumber);
assembler->Bind(&if_rhsisnumber);
{
// Perform the word32 bitwise operation.
var_bitop_lhs.Bind(assembler->TruncateHeapNumberValueToInt32(lhs));
var_bitop_rhs.Bind(assembler->TruncateHeapNumberValueToInt32(rhs));
assembler->Goto(&do_bitop);
}
assembler->Bind(&if_rhsisnotnumber);
{
// Convert the {rhs} to a Number first.
Callable callable =
CodeFactory::NonNumberToNumber(assembler->isolate());
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
assembler->Goto(&loop);
}
}
}
assembler->Bind(&if_lhsisnotnumber);
{
// Convert the {lhs} to a Number first.
Callable callable =
CodeFactory::NonNumberToNumber(assembler->isolate());
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
assembler->Goto(&loop);
}
}
}
assembler->Bind(&do_bitop);
{
Node* lhs_value = var_bitop_lhs.value();
Node* rhs_value = var_bitop_rhs.value();
Node* value = (assembler->*bitop)(lhs_value, rhs_value);
Node* result = assembler->ChangeInt32ToTagged(value);
assembler->Return(result);
}
}
} // namespace
void BitwiseAndStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32And);
using compiler::Node;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
Node* value = assembler->Word32And(lhs_value, rhs_value);
Node* result = assembler->ChangeInt32ToTagged(value);
assembler->Return(result);
}
void BitwiseOrStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32Or);
using compiler::Node;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
Node* value = assembler->Word32Or(lhs_value, rhs_value);
Node* result = assembler->ChangeInt32ToTagged(value);
assembler->Return(result);
}
void BitwiseXorStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateBitwiseOperation(assembler, &compiler::CodeStubAssembler::Word32Xor);
using compiler::Node;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
Node* value = assembler->Word32Xor(lhs_value, rhs_value);
Node* result = assembler->ChangeInt32ToTagged(value);
assembler->Return(result);
}
namespace {
......
......@@ -161,7 +161,7 @@ Node* CodeStubAssembler::SmiUntag(Node* value) {
return raw_assembler_->WordSar(value, SmiShiftBitsConstant());
}
Node* CodeStubAssembler::SmiToInt32(Node* value) {
Node* CodeStubAssembler::SmiToWord32(Node* value) {
Node* result = raw_assembler_->WordSar(value, SmiShiftBitsConstant());
if (raw_assembler_->machine()->Is64()) {
result = raw_assembler_->TruncateInt64ToInt32(result);
......@@ -259,7 +259,7 @@ Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value);
}
Node* CodeStubAssembler::TruncateHeapNumberValueToInt32(Node* object) {
Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node* object) {
Node* value = LoadHeapNumberValue(object);
return raw_assembler_->TruncateFloat64ToInt32(TruncationMode::kJavaScript,
value);
......@@ -537,6 +537,108 @@ Node* CodeStubAssembler::ChangeInt32ToTagged(Node* value) {
return var_result.value();
}
Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
// We might need to loop once due to ToNumber conversion.
Variable var_value(this, MachineRepresentation::kTagged),
var_result(this, MachineRepresentation::kFloat64);
Label loop(this, &var_value), done_loop(this, &var_result);
var_value.Bind(value);
Goto(&loop);
Bind(&loop);
{
// Load the current {value}.
value = var_value.value();
// Check if the {value} is a Smi or a HeapObject.
Label if_valueissmi(this), if_valueisnotsmi(this);
Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
Bind(&if_valueissmi);
{
// Convert the Smi {value}.
var_result.Bind(SmiToFloat64(value));
Goto(&done_loop);
}
Bind(&if_valueisnotsmi);
{
// Check if {value} is a HeapNumber.
Label if_valueisheapnumber(this),
if_valueisnotheapnumber(this, Label::kDeferred);
Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()),
&if_valueisheapnumber, &if_valueisnotheapnumber);
Bind(&if_valueisheapnumber);
{
// Load the floating point value.
var_result.Bind(LoadHeapNumberValue(value));
Goto(&done_loop);
}
Bind(&if_valueisnotheapnumber);
{
// Convert the {value} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_value.Bind(CallStub(callable, context, value));
Goto(&loop);
}
}
}
Bind(&done_loop);
return var_result.value();
}
Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) {
// We might need to loop once due to ToNumber conversion.
Variable var_value(this, MachineRepresentation::kTagged),
var_result(this, MachineRepresentation::kWord32);
Label loop(this, &var_value), done_loop(this, &var_result);
var_value.Bind(value);
Goto(&loop);
Bind(&loop);
{
// Load the current {value}.
value = var_value.value();
// Check if the {value} is a Smi or a HeapObject.
Label if_valueissmi(this), if_valueisnotsmi(this);
Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
Bind(&if_valueissmi);
{
// Convert the Smi {value}.
var_result.Bind(SmiToWord32(value));
Goto(&done_loop);
}
Bind(&if_valueisnotsmi);
{
// Check if {value} is a HeapNumber.
Label if_valueisheapnumber(this),
if_valueisnotheapnumber(this, Label::kDeferred);
Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()),
&if_valueisheapnumber, &if_valueisnotheapnumber);
Bind(&if_valueisheapnumber);
{
// Truncate the floating point value.
var_result.Bind(TruncateHeapNumberValueToWord32(value));
Goto(&done_loop);
}
Bind(&if_valueisnotheapnumber);
{
// Convert the {value} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_value.Bind(CallStub(callable, context, value));
Goto(&loop);
}
}
}
Bind(&done_loop);
return var_result.value();
}
void CodeStubAssembler::BranchIf(Node* condition, Label* if_true,
Label* if_false) {
Label if_condition_is_true(this), if_condition_is_false(this);
......
......@@ -264,7 +264,7 @@ class CodeStubAssembler {
// Smi conversions.
Node* SmiToFloat64(Node* value);
Node* SmiToInt32(Node* value);
Node* SmiToWord32(Node* value);
// Smi operations.
Node* SmiAdd(Node* a, Node* b);
......@@ -296,7 +296,7 @@ class CodeStubAssembler {
// Store the floating point value of a HeapNumber.
Node* StoreHeapNumberValue(Node* object, Node* value);
// Truncate the floating point value of a HeapNumber to an Int32.
Node* TruncateHeapNumberValueToInt32(Node* object);
Node* TruncateHeapNumberValueToWord32(Node* object);
// Load the bit field of a Map.
Node* LoadMapBitField(Node* map);
// Load the instance type of a Map.
......@@ -334,6 +334,8 @@ class CodeStubAssembler {
// Conversions.
Node* ChangeInt32ToTagged(Node* value);
Node* TruncateTaggedToFloat64(Node* context, Node* value);
Node* TruncateTaggedToWord32(Node* context, Node* value);
// Branching helpers.
// TODO(danno): Can we be more cleverish wrt. edge-split?
......
......@@ -319,8 +319,8 @@ TEST(JSFunction) {
const int kNumParams = 3; // Receiver, left, right.
Isolate* isolate(CcTest::InitIsolateOnce());
CodeStubAssemblerTester m(isolate, kNumParams);
m.Return(m.SmiTag(
m.Int32Add(m.SmiToInt32(m.Parameter(1)), m.SmiToInt32(m.Parameter(2)))));
m.Return(m.SmiTag(m.Int32Add(m.SmiToWord32(m.Parameter(1)),
m.SmiToWord32(m.Parameter(2)))));
Handle<Code> code = m.GenerateCode();
Handle<JSFunction> function = CreateFunctionFromCode(kNumParams, code);
Handle<Object> args[] = {Handle<Smi>(Smi::FromInt(23), isolate),
......
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