From: olivf@chromium.org Date: Thu, 20 Jun 2013 13:51:03 +0000 (+0000) Subject: Let NaN flow as double into HBranch + some minor improvements X-Git-Tag: upstream/4.7.83~13747 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=29d3461529a9c355564a9d1b4f7293126353d33f;p=platform%2Fupstream%2Fv8.git Let NaN flow as double into HBranch + some minor improvements BUG= R=verwaest@chromium.org Review URL: https://codereview.chromium.org/17082003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15246 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 1b1294f..f222c29 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -999,10 +999,13 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { LBranch* result = new(zone()) LBranch(UseRegister(value)); // Tagged values that are not known smis or booleans require a - // deoptimization environment. + // deoptimization environment. If the instruction is generic no + // environment is needed since all cases are handled. Representation rep = value->representation(); HType type = value->type(); - if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) { + ToBooleanStub::Types expected = instr->expected_input_types(); + if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() && + !expected.IsGeneric()) { return AssignEnvironment(result); } return result; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 431bb38..2d9c3cd 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2196,7 +2196,7 @@ void LCodeGen::DoBranch(LBranch* instr) { DwVfpRegister reg = ToDoubleRegister(instr->value()); // Test the double value. Zero and NaN are false. __ VFPCompareAndSetFlags(reg, 0.0); - __ cmp(r0, r0, vs); // If NaN, set the Z flag. + __ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN -> false) EmitBranch(instr, ne); } else { ASSERT(r.IsTagged()); @@ -2210,10 +2210,26 @@ void LCodeGen::DoBranch(LBranch* instr) { ASSERT(!info()->IsStub()); __ cmp(reg, Operand::Zero()); EmitBranch(instr, ne); + } else if (type.IsJSArray()) { + ASSERT(!info()->IsStub()); + EmitBranch(instr, al); + } else if (type.IsHeapNumber()) { + ASSERT(!info()->IsStub()); + DwVfpRegister dbl_scratch = double_scratch0(); + __ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); + // Test the double value. Zero and NaN are false. + __ VFPCompareAndSetFlags(dbl_scratch, 0.0); + __ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN) + EmitBranch(instr, ne); + } else if (type.IsString()) { + ASSERT(!info()->IsStub()); + __ ldr(ip, FieldMemOperand(reg, String::kLengthOffset)); + __ cmp(ip, Operand::Zero()); + EmitBranch(instr, ne); } else { ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); // Avoid deopts in the case where we've never executed this path before. - if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); + if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); if (expected.Contains(ToBooleanStub::UNDEFINED)) { // undefined -> false. @@ -2294,8 +2310,11 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_heap_number); } - // We've seen something for the first time -> deopt. - DeoptimizeIf(al, instr->environment()); + if (!expected.IsGeneric()) { + // We've seen something for the first time -> deopt. + // This can only happen if we are not generic already. + DeoptimizeIf(al, instr->environment()); + } } } } diff --git a/src/code-stubs.h b/src/code-stubs.h index edbc93d..c4f0c4d 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -1973,7 +1973,7 @@ class ToBooleanStub: public HydrogenCodeStub { class Types : public EnumSet { public: - Types() {} + Types() : EnumSet(0) {} explicit Types(byte bits) : EnumSet(bits) {} byte ToByte() const { return ToIntegral(); } @@ -1982,10 +1982,10 @@ class ToBooleanStub: public HydrogenCodeStub { bool Record(Handle object); bool NeedsMap() const; bool CanBeUndetectable() const; - }; + bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); } - static Types no_types() { return Types(); } - static Types all_types() { return Types((1 << NUMBER_OF_TYPES) - 1); } + static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); } + }; explicit ToBooleanStub(Types types = Types()) : types_(types) { } diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 3765a98..f746af5 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1277,20 +1277,26 @@ void HReturn::PrintDataTo(StringStream* stream) { Representation HBranch::observed_input_representation(int index) { static const ToBooleanStub::Types tagged_types( - ToBooleanStub::UNDEFINED | ToBooleanStub::NULL_TYPE | ToBooleanStub::SPEC_OBJECT | ToBooleanStub::STRING | ToBooleanStub::SYMBOL); if (expected_input_types_.ContainsAnyOf(tagged_types)) { return Representation::Tagged(); - } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { + } + if (expected_input_types_.Contains(ToBooleanStub::UNDEFINED)) { + if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { + return Representation::Double(); + } + return Representation::Tagged(); + } + if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { return Representation::Double(); - } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) { + } + if (expected_input_types_.Contains(ToBooleanStub::SMI)) { return Representation::Smi(); - } else { - return Representation::None(); } + return Representation::None(); } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 2b36775..4ed0187 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -1599,17 +1599,21 @@ class HBranch: public HUnaryControlInstruction { HBranch(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target, - ToBooleanStub::Types expected_input_types = ToBooleanStub::no_types()) + ToBooleanStub::Types expected_input_types = ToBooleanStub::Types()) : HUnaryControlInstruction(value, true_target, false_target), expected_input_types_(expected_input_types) { ASSERT(true_target != NULL && false_target != NULL); + SetFlag(kAllowUndefinedAsNaN); } explicit HBranch(HValue* value) - : HUnaryControlInstruction(value, NULL, NULL) { } + : HUnaryControlInstruction(value, NULL, NULL) { + SetFlag(kAllowUndefinedAsNaN); + } HBranch(HValue* value, ToBooleanStub::Types expected_input_types) : HUnaryControlInstruction(value, NULL, NULL), - expected_input_types_(expected_input_types) { } - + expected_input_types_(expected_input_types) { + SetFlag(kAllowUndefinedAsNaN); + } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 21de99d..940973e 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -803,7 +803,7 @@ void HGraphBuilder::IfBuilder::Then() { // so that the graph builder visits it and sees any live range extending // constructs within it. HConstant* constant_false = builder_->graph()->GetConstantFalse(); - ToBooleanStub::Types boolean_type = ToBooleanStub::no_types(); + ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); boolean_type.Add(ToBooleanStub::BOOLEAN); HBranch* branch = new(zone()) HBranch(constant_false, first_true_block_, diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 28164c7..29bdc1d 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2133,10 +2133,22 @@ void LCodeGen::DoBranch(LBranch* instr) { ASSERT(!info()->IsStub()); __ test(reg, Operand(reg)); EmitBranch(instr, not_equal); + } else if (type.IsJSArray()) { + ASSERT(!info()->IsStub()); + EmitBranch(instr, no_condition); + } else if (type.IsHeapNumber()) { + ASSERT(!info()->IsStub()); + CpuFeatureScope scope(masm(), SSE2); + __ xorps(xmm0, xmm0); + __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); + EmitBranch(instr, not_equal); + } else if (type.IsString()) { + ASSERT(!info()->IsStub()); + __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); + EmitBranch(instr, not_equal); } else { ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); - // Avoid deopts in the case where we've never executed this path before. - if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); + if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); if (expected.Contains(ToBooleanStub::UNDEFINED)) { // undefined -> false. @@ -2225,8 +2237,11 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_heap_number); } - // We've seen something for the first time -> deopt. - DeoptimizeIf(no_condition, instr->environment()); + if (!expected.IsGeneric()) { + // We've seen something for the first time -> deopt. + // This can only happen if we are not generic already. + DeoptimizeIf(no_condition, instr->environment()); + } } } } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index ed85c0e..96fbc8a 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1060,20 +1060,28 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { return new(zone()) LGoto(successor->block_id()); } - // Untagged integers or doubles, smis and booleans don't require a - // deoptimization environment nor a temp register. + ToBooleanStub::Types expected = instr->expected_input_types(); + + // Tagged values that are not known smis or booleans require a + // deoptimization environment. If the instruction is generic no + // environment is needed since all cases are handled. Representation rep = value->representation(); HType type = value->type(); if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) { return new(zone()) LBranch(UseRegister(value), NULL); } - ToBooleanStub::Types expected = instr->expected_input_types(); + bool needs_temp = expected.NeedsMap() || expected.IsEmpty(); + LOperand* temp = needs_temp ? TempRegister() : NULL; + + // The Generic stub does not have a deopt, so we need no environment. + if (expected.IsGeneric()) { + return new(zone()) LBranch(UseRegister(value), temp); + } + // We need a temporary register when we have to access the map *or* we have // no type info yet, in which case we handle all cases (including the ones // involving maps). - bool needs_temp = expected.NeedsMap() || expected.IsEmpty(); - LOperand* temp = needs_temp ? TempRegister() : NULL; return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp)); } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 1dac13d..296458f 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -1919,10 +1919,22 @@ void LCodeGen::DoBranch(LBranch* instr) { ASSERT(!info()->IsStub()); __ SmiCompare(reg, Smi::FromInt(0)); EmitBranch(instr, not_equal); + } else if (type.IsJSArray()) { + ASSERT(!info()->IsStub()); + EmitBranch(instr, no_condition); + } else if (type.IsHeapNumber()) { + ASSERT(!info()->IsStub()); + __ xorps(xmm0, xmm0); + __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); + EmitBranch(instr, not_equal); + } else if (type.IsString()) { + ASSERT(!info()->IsStub()); + __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0)); + EmitBranch(instr, not_equal); } else { ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); // Avoid deopts in the case where we've never executed this path before. - if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); + if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); if (expected.Contains(ToBooleanStub::UNDEFINED)) { // undefined -> false. @@ -1995,8 +2007,11 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_heap_number); } - // We've seen something for the first time -> deopt. - DeoptimizeIf(no_condition, instr->environment()); + if (!expected.IsGeneric()) { + // We've seen something for the first time -> deopt. + // This can only happen if we are not generic already. + DeoptimizeIf(no_condition, instr->environment()); + } } } } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index b1bc547..5b15cec 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1014,10 +1014,13 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { LBranch* result = new(zone()) LBranch(UseRegister(value)); // Tagged values that are not known smis or booleans require a - // deoptimization environment. + // deoptimization environment. If the instruction is generic no + // environment is needed since all cases are handled. + ToBooleanStub::Types expected = instr->expected_input_types(); Representation rep = value->representation(); HType type = value->type(); - if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) { + if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() && + !expected.IsGeneric()) { return AssignEnvironment(result); } return result;