Commit 7d383be9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[crankshaft] Support all oddballs for truncating TaggedToI changes.

For inputs to truncating binary operations like <<, | or >>>, support
all Oddballs not just undefined, true and false. This unifies treatment
of these truncations in Crankshaft and TurboFan, and is very easy
nowadays, since the memory layout of Oddball and HeapNumber is
compatible.

R=yangguo@chromium.org
BUG=v8:5400

Review-Url: https://codereview.chromium.org/2452193003
Cr-Commit-Position: refs/heads/master@{#40608}
parent 9bc155b9
......@@ -318,7 +318,7 @@ OsrGuardType OsrGuardTypeOf(Operator const* op) {
V(LostPrecisionOrNaN) \
V(NoReason) \
V(NotAHeapNumber) \
V(NotAHeapNumberUndefinedBoolean) \
V(NotANumberOrOddball) \
V(NotASmi) \
V(OutOfBounds) \
V(WrongInstanceType) \
......
......@@ -1818,8 +1818,7 @@ EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
graph()->NewNode(machine()->Word32Equal(), instance_type,
jsgraph()->Int32Constant(ODDBALL_TYPE));
if_false = efalse = graph()->NewNode(
common()->DeoptimizeUnless(
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean),
common()->DeoptimizeUnless(DeoptimizeReason::kNotANumberOrOddball),
check_oddball, frame_state, efalse, if_false);
STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
......
......@@ -4538,34 +4538,12 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
__ cmp(scratch1, Operand(ip));
if (instr->truncating()) {
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations.
Label no_heap_number, check_bools, check_false;
__ b(ne, &no_heap_number);
Label truncate;
__ b(eq, &truncate);
__ CompareInstanceType(scratch1, scratch1, ODDBALL_TYPE);
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotANumberOrOddball);
__ bind(&truncate);
__ TruncateHeapNumberToI(input_reg, scratch2);
__ b(&done);
// Check for Oddballs. Undefined/False is converted to zero and True to one
// for truncating conversions.
__ bind(&no_heap_number);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(scratch2, Operand(ip));
__ b(ne, &check_bools);
__ mov(input_reg, Operand::Zero());
__ b(&done);
__ bind(&check_bools);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(scratch2, Operand(ip));
__ b(ne, &check_false);
__ mov(input_reg, Operand(1));
__ b(&done);
__ bind(&check_false);
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ cmp(scratch2, Operand(ip));
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumberUndefinedBoolean);
__ mov(input_reg, Operand::Zero());
} else {
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumber);
......
......@@ -5181,30 +5181,18 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr,
Label done;
if (instr->truncating()) {
UseScratchRegisterScope temps(masm());
Register output = ToRegister(instr->result());
Label check_bools;
// If it's not a heap number, jump to undefined check.
__ JumpIfNotHeapNumber(input, &check_bools);
// A heap number: load value and convert to int32 using truncating function.
Register input_map = temps.AcquireX();
Register input_instance_type = input_map;
Label truncate;
__ CompareObjectType(input, input_map, input_instance_type,
HEAP_NUMBER_TYPE);
__ B(eq, &truncate);
__ Cmp(input_instance_type, ODDBALL_TYPE);
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotANumberOrOddball);
__ Bind(&truncate);
__ TruncateHeapNumberToI(output, input);
__ B(&done);
__ Bind(&check_bools);
Register true_root = output;
Register false_root = scratch1;
__ LoadTrueFalseRoots(true_root, false_root);
__ Cmp(input, true_root);
__ Cset(output, eq);
__ Ccmp(input, false_root, ZFlag, ne);
__ B(eq, &done);
// Output contains zero, undefined is converted to zero for truncating
// conversions.
DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean);
} else {
Register output = ToRegister32(instr->result());
DoubleRegister dbl_scratch2 = ToDoubleRegister(temp2);
......
......@@ -4308,34 +4308,18 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
__ lea(input_reg, Operand(input_reg, times_2, kHeapObjectTag));
if (instr->truncating()) {
Label no_heap_number, check_bools, check_false;
// Heap number map check.
Label truncate;
Label::Distance truncate_distance =
DeoptEveryNTimes() ? Label::kFar : Label::kNear;
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
__ j(not_equal, &no_heap_number, Label::kNear);
__ j(equal, &truncate, truncate_distance);
__ push(input_reg);
__ CmpObjectType(input_reg, ODDBALL_TYPE, input_reg);
__ pop(input_reg);
DeoptimizeIf(not_equal, instr, DeoptimizeReason::kNotANumberOrOddball);
__ bind(&truncate);
__ TruncateHeapNumberToI(input_reg, input_reg);
__ jmp(done);
__ bind(&no_heap_number);
// Check for Oddballs. Undefined/False is converted to zero and True to one
// for truncating conversions.
__ cmp(input_reg, factory()->undefined_value());
__ j(not_equal, &check_bools, Label::kNear);
__ Move(input_reg, Immediate(0));
__ jmp(done);
__ bind(&check_bools);
__ cmp(input_reg, factory()->true_value());
__ j(not_equal, &check_false, Label::kNear);
__ Move(input_reg, Immediate(1));
__ jmp(done);
__ bind(&check_false);
__ cmp(input_reg, factory()->false_value());
DeoptimizeIf(not_equal, instr,
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean);
__ Move(input_reg, Immediate(0));
} else {
XMMRegister scratch = ToDoubleRegister(instr->temp());
DCHECK(!scratch.is(xmm0));
......
......@@ -4487,36 +4487,14 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
// of the if.
if (instr->truncating()) {
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations.
Label no_heap_number, check_bools, check_false;
// Check HeapNumber map.
__ Branch(USE_DELAY_SLOT, &no_heap_number, ne, scratch1, Operand(at));
Label truncate;
__ Branch(USE_DELAY_SLOT, &truncate, eq, scratch1, Operand(at));
__ mov(scratch2, input_reg); // In delay slot.
__ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotANumberOrOddball, scratch1,
Operand(ODDBALL_TYPE));
__ bind(&truncate);
__ TruncateHeapNumberToI(input_reg, scratch2);
__ Branch(&done);
// Check for Oddballs. Undefined/False is converted to zero and True to one
// for truncating conversions.
__ bind(&no_heap_number);
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(&check_bools, ne, input_reg, Operand(at));
DCHECK(ToRegister(instr->result()).is(input_reg));
__ Branch(USE_DELAY_SLOT, &done);
__ mov(input_reg, zero_reg); // In delay slot.
__ bind(&check_bools);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(&check_false, ne, scratch2, Operand(at));
__ Branch(USE_DELAY_SLOT, &done);
__ li(input_reg, Operand(1)); // In delay slot.
__ bind(&check_false);
__ LoadRoot(at, Heap::kFalseValueRootIndex);
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumberUndefinedBoolean,
scratch2, Operand(at));
__ Branch(USE_DELAY_SLOT, &done);
__ mov(input_reg, zero_reg); // In delay slot.
} else {
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumber, scratch1,
Operand(at));
......
......@@ -4695,36 +4695,14 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
// of the if.
if (instr->truncating()) {
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations.
Label no_heap_number, check_bools, check_false;
// Check HeapNumber map.
__ Branch(USE_DELAY_SLOT, &no_heap_number, ne, scratch1, Operand(at));
Label truncate;
__ Branch(USE_DELAY_SLOT, &truncate, eq, scratch1, Operand(at));
__ mov(scratch2, input_reg); // In delay slot.
__ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotANumberOrOddball, scratch1,
Operand(ODDBALL_TYPE));
__ bind(&truncate);
__ TruncateHeapNumberToI(input_reg, scratch2);
__ Branch(&done);
// Check for Oddballs. Undefined/False is converted to zero and True to one
// for truncating conversions.
__ bind(&no_heap_number);
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(&check_bools, ne, input_reg, Operand(at));
DCHECK(ToRegister(instr->result()).is(input_reg));
__ Branch(USE_DELAY_SLOT, &done);
__ mov(input_reg, zero_reg); // In delay slot.
__ bind(&check_bools);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(&check_false, ne, scratch2, Operand(at));
__ Branch(USE_DELAY_SLOT, &done);
__ li(input_reg, Operand(1)); // In delay slot.
__ bind(&check_false);
__ LoadRoot(at, Heap::kFalseValueRootIndex);
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumberUndefinedBoolean,
scratch2, Operand(at));
__ Branch(USE_DELAY_SLOT, &done);
__ mov(input_reg, zero_reg); // In delay slot.
} else {
DeoptimizeIf(ne, instr, DeoptimizeReason::kNotAHeapNumber, scratch1,
Operand(at));
......
......@@ -4594,34 +4594,17 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
Register input_reg = ToRegister(instr->value());
if (instr->truncating()) {
Label no_heap_number, check_bools, check_false;
// Heap number map check.
__ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &no_heap_number, Label::kNear);
Register input_map_reg = kScratchRegister;
Label truncate;
Label::Distance truncate_distance =
DeoptEveryNTimes() ? Label::kFar : Label::kNear;
__ movp(input_map_reg, FieldOperand(input_reg, HeapObject::kMapOffset));
__ JumpIfRoot(input_map_reg, Heap::kHeapNumberMapRootIndex, &truncate,
truncate_distance);
__ CmpInstanceType(input_map_reg, ODDBALL_TYPE);
DeoptimizeIf(not_equal, instr, DeoptimizeReason::kNotANumberOrOddball);
__ bind(&truncate);
__ TruncateHeapNumberToI(input_reg, input_reg);
__ jmp(done);
__ bind(&no_heap_number);
// Check for Oddballs. Undefined/False is converted to zero and True to one
// for truncating conversions.
__ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &check_bools, Label::kNear);
__ Set(input_reg, 0);
__ jmp(done);
__ bind(&check_bools);
__ CompareRoot(input_reg, Heap::kTrueValueRootIndex);
__ j(not_equal, &check_false, Label::kNear);
__ Set(input_reg, 1);
__ jmp(done);
__ bind(&check_false);
__ CompareRoot(input_reg, Heap::kFalseValueRootIndex);
DeoptimizeIf(not_equal, instr,
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean);
__ Set(input_reg, 0);
} else {
XMMRegister scratch = ToDoubleRegister(instr->temp());
DCHECK(!scratch.is(double_scratch0()));
......
This diff is collapsed.
......@@ -270,8 +270,8 @@ BinaryOpICState::Kind BinaryOpICState::UpdateKind(Handle<Object> object,
Kind kind) const {
Kind new_kind = GENERIC;
bool is_truncating = Token::IsTruncatingBinaryOp(op());
if (object->IsBoolean() && is_truncating) {
// Booleans will be automatically truncated by HChange.
if (object->IsOddball() && is_truncating) {
// Oddballs will be automatically truncated by HChange.
new_kind = INT32;
} else if (object->IsUndefined(isolate_)) {
// Undefined will be automatically truncated by HChange.
......
// 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.
// Flags: --allow-natives-syntax
(function() {
function foo(x, y) { return x << y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
(function() {
function foo(x, y) { return x >> y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
(function() {
function foo(x, y) { return x >>> y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
(function() {
function foo(x, y) { return x ^ y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
(function() {
function foo(x, y) { return x | y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
(function() {
function foo(x, y) { return x & y; }
foo(1.1, 0.1);
%BaselineFunctionOnNextCall(foo);
foo(0.1, 1.1);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
foo(1.1, undefined);
assertOptimized(foo);
foo(null, 1.1);
assertOptimized(foo);
foo(1.1, null);
assertOptimized(foo);
foo(true, 1.1);
assertOptimized(foo);
foo(1.1, true);
assertOptimized(foo);
foo(false, 1.1);
assertOptimized(foo);
foo(1.1, false);
assertOptimized(foo);
})();
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