Commit 9019de38 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

Add NumberAdd/NumberSub methods to CSA

These will be used in subsequent CLs to add spec-compliant builtins
on Array.prototype built with the CSA.

Change-Id: I4c9f72f90dffe018b99efdc73e9d40b3d175c2aa
Reviewed-on: https://chromium-review.googlesource.com/704115Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48362}
parent 1aa09302
...@@ -9603,6 +9603,66 @@ Node* CodeStubAssembler::NumberDec(Node* value) { ...@@ -9603,6 +9603,66 @@ Node* CodeStubAssembler::NumberDec(Node* value) {
return var_result.value(); return var_result.value();
} }
Node* CodeStubAssembler::NumberAdd(Node* a, Node* b) {
VARIABLE(var_result, MachineRepresentation::kTagged);
VARIABLE(var_fadd_value, MachineRepresentation::kFloat64);
Label float_add(this, Label::kDeferred), end(this);
GotoIf(TaggedIsNotSmi(a), &float_add);
GotoIf(TaggedIsNotSmi(b), &float_add);
// Try fast Smi addition first.
Node* pair =
IntPtrAddWithOverflow(BitcastTaggedToWord(a), BitcastTaggedToWord(b));
Node* overflow = Projection(1, pair);
// Check if the Smi addition overflowed.
Label if_overflow(this), if_notoverflow(this);
GotoIf(overflow, &float_add);
var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
Goto(&end);
BIND(&float_add);
{
var_result.Bind(ChangeFloat64ToTagged(
Float64Add(ChangeNumberToFloat64(a), ChangeNumberToFloat64(b))));
Goto(&end);
}
BIND(&end);
return var_result.value();
}
Node* CodeStubAssembler::NumberSub(Node* a, Node* b) {
VARIABLE(var_result, MachineRepresentation::kTagged);
VARIABLE(var_fsub_value, MachineRepresentation::kFloat64);
Label float_sub(this, Label::kDeferred), end(this);
GotoIf(TaggedIsNotSmi(a), &float_sub);
GotoIf(TaggedIsNotSmi(b), &float_sub);
// Try fast Smi subtraction first.
Node* pair =
IntPtrSubWithOverflow(BitcastTaggedToWord(a), BitcastTaggedToWord(b));
Node* overflow = Projection(1, pair);
// Check if the Smi subtraction overflowed.
Label if_overflow(this), if_notoverflow(this);
GotoIf(overflow, &float_sub);
var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
Goto(&end);
BIND(&float_sub);
{
var_result.Bind(ChangeFloat64ToTagged(
Float64Sub(ChangeNumberToFloat64(a), ChangeNumberToFloat64(b))));
Goto(&end);
}
BIND(&end);
return var_result.value();
}
void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) { void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) {
Label is_number(this); Label is_number(this);
GotoIf(TaggedIsSmi(input), &is_number); GotoIf(TaggedIsSmi(input), &is_number);
......
...@@ -279,6 +279,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -279,6 +279,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// Smi | HeapNumber operations. // Smi | HeapNumber operations.
Node* NumberInc(Node* value); Node* NumberInc(Node* value);
Node* NumberDec(Node* value); Node* NumberDec(Node* value);
Node* NumberAdd(Node* a, Node* b);
Node* NumberSub(Node* a, Node* b);
void GotoIfNotNumber(Node* value, Label* is_not_number); void GotoIfNotNumber(Node* value, Label* is_not_number);
void GotoIfNumber(Node* value, Label* is_number); void GotoIfNumber(Node* value, Label* is_number);
......
...@@ -2804,6 +2804,50 @@ TEST(NumberMinMax) { ...@@ -2804,6 +2804,50 @@ TEST(NumberMinMax) {
CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_b, smi_5)->value(), 3.5); CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_b, smi_5)->value(), 3.5);
} }
TEST(NumberAddSub) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 2;
CodeAssemblerTester asm_tester_add(isolate, kNumParams);
{
CodeStubAssembler m(asm_tester_add.state());
m.Return(m.NumberAdd(m.Parameter(0), m.Parameter(1)));
}
FunctionTester ft_add(asm_tester_add.GenerateCode(), kNumParams);
CodeAssemblerTester asm_tester_sub(isolate, kNumParams);
{
CodeStubAssembler m(asm_tester_sub.state());
m.Return(m.NumberSub(m.Parameter(0), m.Parameter(1)));
}
FunctionTester ft_sub(asm_tester_sub.GenerateCode(), kNumParams);
// Test smi values.
Handle<Smi> smi_1(Smi::FromInt(1), isolate);
Handle<Smi> smi_2(Smi::FromInt(2), isolate);
CHECK_EQ(ft_add.CallChecked<Smi>(smi_1, smi_2)->value(), 3);
CHECK_EQ(ft_sub.CallChecked<Smi>(smi_2, smi_1)->value(), 1);
// Test double values.
Handle<Object> double_a = isolate->factory()->NewNumber(2.5);
Handle<Object> double_b = isolate->factory()->NewNumber(3.0);
CHECK_EQ(ft_add.CallChecked<HeapNumber>(double_a, double_b)->value(), 5.5);
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(double_a, double_b)->value(), -.5);
// Test overflow.
Handle<Smi> smi_max(Smi::FromInt(Smi::kMaxValue), isolate);
Handle<Smi> smi_min(Smi::FromInt(Smi::kMinValue), isolate);
CHECK_EQ(ft_add.CallChecked<HeapNumber>(smi_max, smi_1)->value(),
static_cast<double>(Smi::kMaxValue) + 1);
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(smi_min, smi_1)->value(),
static_cast<double>(Smi::kMinValue) - 1);
// Test mixed smi/double values.
CHECK_EQ(ft_add.CallChecked<HeapNumber>(smi_1, double_a)->value(), 3.5);
CHECK_EQ(ft_add.CallChecked<HeapNumber>(double_a, smi_1)->value(), 3.5);
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(smi_1, double_a)->value(), -1.5);
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(double_a, smi_1)->value(), 1.5);
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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