From: whesse@chromium.org Date: Thu, 15 Jul 2010 10:34:08 +0000 (+0000) Subject: Avoid a smi check when comparing an unknown to a constant smi for equality on ia32... X-Git-Tag: upstream/4.7.83~21486 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dd06f4f102f479fb34119fdd2f13fab42fe85aac;p=platform%2Fupstream%2Fv8.git Avoid a smi check when comparing an unknown to a constant smi for equality on ia32 and x64 platforms. Review URL: http://codereview.chromium.org/2897013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5077 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index be5442e..2f46d96 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -2487,8 +2487,7 @@ void CodeGenerator::Comparison(AstNode* node, } ASSERT(cc == less || cc == equal || cc == greater_equal); - // If either side is a constant of some sort, we can probably optimize the - // comparison. + // If either side is a constant smi, optimize the comparison. bool left_side_constant_smi = false; bool left_side_constant_null = false; bool left_side_constant_1_char_string = false; @@ -2513,114 +2512,11 @@ void CodeGenerator::Comparison(AstNode* node, } if (left_side_constant_smi || right_side_constant_smi) { - if (left_side_constant_smi && right_side_constant_smi) { - // Trivial case, comparing two constants. - int left_value = Smi::cast(*left_side.handle())->value(); - int right_value = Smi::cast(*right_side.handle())->value(); - switch (cc) { - case less: - dest->Goto(left_value < right_value); - break; - case equal: - dest->Goto(left_value == right_value); - break; - case greater_equal: - dest->Goto(left_value >= right_value); - break; - default: - UNREACHABLE(); - } - } else { - // Only one side is a constant Smi. - // If left side is a constant Smi, reverse the operands. - // Since one side is a constant Smi, conversion order does not matter. - if (left_side_constant_smi) { - Result temp = left_side; - left_side = right_side; - right_side = temp; - cc = ReverseCondition(cc); - // This may re-introduce greater or less_equal as the value of cc. - // CompareStub and the inline code both support all values of cc. - } - // Implement comparison against a constant Smi, inlining the case - // where both sides are Smis. - left_side.ToRegister(); - Register left_reg = left_side.reg(); - Handle right_val = right_side.handle(); - - // Here we split control flow to the stub call and inlined cases - // before finally splitting it to the control destination. We use - // a jump target and branching to duplicate the virtual frame at - // the first split. We manually handle the off-frame references - // by reconstituting them on the non-fall-through path. - - if (left_side.is_smi()) { - if (FLAG_debug_code) { - __ AbortIfNotSmi(left_side.reg()); - } - } else { - JumpTarget is_smi; - __ test(left_side.reg(), Immediate(kSmiTagMask)); - is_smi.Branch(zero, taken); - - bool is_loop_condition = (node->AsExpression() != NULL) && - node->AsExpression()->is_loop_condition(); - if (!is_loop_condition && - CpuFeatures::IsSupported(SSE2) && - right_val->IsSmi()) { - // Right side is a constant smi and left side has been checked - // not to be a smi. - CpuFeatures::Scope use_sse2(SSE2); - JumpTarget not_number; - __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), - Immediate(Factory::heap_number_map())); - not_number.Branch(not_equal, &left_side); - __ movdbl(xmm1, - FieldOperand(left_reg, HeapNumber::kValueOffset)); - int value = Smi::cast(*right_val)->value(); - if (value == 0) { - __ xorpd(xmm0, xmm0); - } else { - Result temp = allocator()->Allocate(); - __ mov(temp.reg(), Immediate(value)); - __ cvtsi2sd(xmm0, Operand(temp.reg())); - temp.Unuse(); - } - __ ucomisd(xmm1, xmm0); - // Jump to builtin for NaN. - not_number.Branch(parity_even, &left_side); - left_side.Unuse(); - dest->true_target()->Branch(DoubleCondition(cc)); - dest->false_target()->Jump(); - not_number.Bind(&left_side); - } - - // Setup and call the compare stub. - CompareStub stub(cc, strict, kCantBothBeNaN); - Result result = frame_->CallStub(&stub, &left_side, &right_side); - result.ToRegister(); - __ cmp(result.reg(), 0); - result.Unuse(); - dest->true_target()->Branch(cc); - dest->false_target()->Jump(); - - is_smi.Bind(); - } - - left_side = Result(left_reg); - right_side = Result(right_val); - // Test smi equality and comparison by signed int comparison. - if (IsUnsafeSmi(right_side.handle())) { - right_side.ToRegister(); - __ cmp(left_side.reg(), Operand(right_side.reg())); - } else { - __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); - } - left_side.Unuse(); - right_side.Unuse(); - dest->Split(cc); - } - + bool is_loop_condition = (node->AsExpression() != NULL) && + node->AsExpression()->is_loop_condition(); + ConstantSmiComparison(cc, strict, dest, &left_side, &right_side, + left_side_constant_smi, right_side_constant_smi, + is_loop_condition); } else if (cc == equal && (left_side_constant_null || right_side_constant_null)) { // To make null checks efficient, we check if either the left side or @@ -2882,6 +2778,139 @@ void CodeGenerator::Comparison(AstNode* node, } +void CodeGenerator::ConstantSmiComparison(Condition cc, + bool strict, + ControlDestination* dest, + Result* left_side, + Result* right_side, + bool left_side_constant_smi, + bool right_side_constant_smi, + bool is_loop_condition) { + if (left_side_constant_smi && right_side_constant_smi) { + // Trivial case, comparing two constants. + int left_value = Smi::cast(*left_side->handle())->value(); + int right_value = Smi::cast(*right_side->handle())->value(); + switch (cc) { + case less: + dest->Goto(left_value < right_value); + break; + case equal: + dest->Goto(left_value == right_value); + break; + case greater_equal: + dest->Goto(left_value >= right_value); + break; + default: + UNREACHABLE(); + } + } else { + // Only one side is a constant Smi. + // If left side is a constant Smi, reverse the operands. + // Since one side is a constant Smi, conversion order does not matter. + if (left_side_constant_smi) { + Result* temp = left_side; + left_side = right_side; + right_side = temp; + cc = ReverseCondition(cc); + // This may re-introduce greater or less_equal as the value of cc. + // CompareStub and the inline code both support all values of cc. + } + // Implement comparison against a constant Smi, inlining the case + // where both sides are Smis. + left_side->ToRegister(); + Register left_reg = left_side->reg(); + Handle right_val = right_side->handle(); + + if (left_side->is_smi()) { + if (FLAG_debug_code) { + __ AbortIfNotSmi(left_reg); + } + // Test smi equality and comparison by signed int comparison. + if (IsUnsafeSmi(right_side->handle())) { + right_side->ToRegister(); + __ cmp(left_reg, Operand(right_side->reg())); + } else { + __ cmp(Operand(left_reg), Immediate(right_side->handle())); + } + left_side->Unuse(); + right_side->Unuse(); + dest->Split(cc); + } else { + // Only the case where the left side could possibly be a non-smi is left. + JumpTarget is_smi; + if (cc == equal) { + // We can do the equality comparison before the smi check. + __ cmp(Operand(left_reg), Immediate(right_side->handle())); + dest->true_target()->Branch(equal); + __ test(left_reg, Immediate(kSmiTagMask)); + dest->false_target()->Branch(zero); + } else { + // Do the smi check, then the comparison. + JumpTarget is_not_smi; + __ test(left_reg, Immediate(kSmiTagMask)); + is_smi.Branch(zero, left_side, right_side); + } + + // Jump or fall through to here if we are comparing a non-smi to a + // constant smi. If the non-smi is a heap number and this is not + // a loop condition, inline the floating point code. + if (!is_loop_condition && CpuFeatures::IsSupported(SSE2)) { + // Right side is a constant smi and left side has been checked + // not to be a smi. + CpuFeatures::Scope use_sse2(SSE2); + JumpTarget not_number; + __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), + Immediate(Factory::heap_number_map())); + not_number.Branch(not_equal, left_side); + __ movdbl(xmm1, + FieldOperand(left_reg, HeapNumber::kValueOffset)); + int value = Smi::cast(*right_val)->value(); + if (value == 0) { + __ xorpd(xmm0, xmm0); + } else { + Result temp = allocator()->Allocate(); + __ mov(temp.reg(), Immediate(value)); + __ cvtsi2sd(xmm0, Operand(temp.reg())); + temp.Unuse(); + } + __ ucomisd(xmm1, xmm0); + // Jump to builtin for NaN. + not_number.Branch(parity_even, left_side); + left_side->Unuse(); + dest->true_target()->Branch(DoubleCondition(cc)); + dest->false_target()->Jump(); + not_number.Bind(left_side); + } + + // Setup and call the compare stub. + CompareStub stub(cc, strict, kCantBothBeNaN); + Result result = frame_->CallStub(&stub, left_side, right_side); + result.ToRegister(); + __ test(result.reg(), Operand(result.reg())); + result.Unuse(); + if (cc == equal) { + dest->Split(cc); + } else { + dest->true_target()->Branch(cc); + dest->false_target()->Jump(); + + // It is important for performance for this case to be at the end. + is_smi.Bind(left_side, right_side); + if (IsUnsafeSmi(right_side->handle())) { + right_side->ToRegister(); + __ cmp(left_reg, Operand(right_side->reg())); + } else { + __ cmp(Operand(left_reg), Immediate(right_side->handle())); + } + left_side->Unuse(); + right_side->Unuse(); + dest->Split(cc); + } + } + } +} + + // Check that the comparison operand is a number. Jump to not_numbers jump // target passing the left and right result if the operand is not a number. static void CheckComparisonOperand(MacroAssembler* masm_, diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index a432c13..a7db0b3 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -560,6 +560,17 @@ class CodeGenerator: public AstVisitor { Condition cc, bool strict, ControlDestination* destination); + + // If at least one of the sides is a constant smi, generate optimized code. + void ConstantSmiComparison(Condition cc, + bool strict, + ControlDestination* destination, + Result* left_side, + Result* right_side, + bool left_side_constant_smi, + bool right_side_constant_smi, + bool is_loop_condition); + void GenerateInlineNumberComparison(Result* left_side, Result* right_side, Condition cc, diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 72e7cb3..d8ae0b1 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -2002,106 +2002,11 @@ void CodeGenerator::Comparison(AstNode* node, } if (left_side_constant_smi || right_side_constant_smi) { - if (left_side_constant_smi && right_side_constant_smi) { - // Trivial case, comparing two constants. - int left_value = Smi::cast(*left_side.handle())->value(); - int right_value = Smi::cast(*right_side.handle())->value(); - switch (cc) { - case less: - dest->Goto(left_value < right_value); - break; - case equal: - dest->Goto(left_value == right_value); - break; - case greater_equal: - dest->Goto(left_value >= right_value); - break; - default: - UNREACHABLE(); - } - } else { - // Only one side is a constant Smi. - // If left side is a constant Smi, reverse the operands. - // Since one side is a constant Smi, conversion order does not matter. - if (left_side_constant_smi) { - Result temp = left_side; - left_side = right_side; - right_side = temp; - cc = ReverseCondition(cc); - // This may re-introduce greater or less_equal as the value of cc. - // CompareStub and the inline code both support all values of cc. - } - // Implement comparison against a constant Smi, inlining the case - // where both sides are Smis. - left_side.ToRegister(); - Register left_reg = left_side.reg(); - Handle right_val = right_side.handle(); - - // Here we split control flow to the stub call and inlined cases - // before finally splitting it to the control destination. We use - // a jump target and branching to duplicate the virtual frame at - // the first split. We manually handle the off-frame references - // by reconstituting them on the non-fall-through path. - JumpTarget is_smi; - - if (left_side.is_smi()) { - if (FLAG_debug_code) { - __ AbortIfNotSmi(left_side.reg()); - } - } else { - Condition left_is_smi = masm_->CheckSmi(left_side.reg()); - is_smi.Branch(left_is_smi); - - bool is_loop_condition = (node->AsExpression() != NULL) && - node->AsExpression()->is_loop_condition(); - if (!is_loop_condition && right_val->IsSmi()) { - // Right side is a constant smi and left side has been checked - // not to be a smi. - JumpTarget not_number; - __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), - Factory::heap_number_map()); - not_number.Branch(not_equal, &left_side); - __ movsd(xmm1, - FieldOperand(left_reg, HeapNumber::kValueOffset)); - int value = Smi::cast(*right_val)->value(); - if (value == 0) { - __ xorpd(xmm0, xmm0); - } else { - Result temp = allocator()->Allocate(); - __ movl(temp.reg(), Immediate(value)); - __ cvtlsi2sd(xmm0, temp.reg()); - temp.Unuse(); - } - __ ucomisd(xmm1, xmm0); - // Jump to builtin for NaN. - not_number.Branch(parity_even, &left_side); - left_side.Unuse(); - dest->true_target()->Branch(DoubleCondition(cc)); - dest->false_target()->Jump(); - not_number.Bind(&left_side); - } - - // Setup and call the compare stub. - CompareStub stub(cc, strict, kCantBothBeNaN); - Result result = frame_->CallStub(&stub, &left_side, &right_side); - result.ToRegister(); - __ testq(result.reg(), result.reg()); - result.Unuse(); - dest->true_target()->Branch(cc); - dest->false_target()->Jump(); - - is_smi.Bind(); - } - - left_side = Result(left_reg); - right_side = Result(right_val); - // Test smi equality and comparison by signed int comparison. - // Both sides are smis, so we can use an Immediate. - __ SmiCompare(left_side.reg(), Smi::cast(*right_side.handle())); - left_side.Unuse(); - right_side.Unuse(); - dest->Split(cc); - } + bool is_loop_condition = (node->AsExpression() != NULL) && + node->AsExpression()->is_loop_condition(); + ConstantSmiComparison(cc, strict, dest, &left_side, &right_side, + left_side_constant_smi, right_side_constant_smi, + is_loop_condition); } else if (cc == equal && (left_side_constant_null || right_side_constant_null)) { // To make null checks efficient, we check if either the left side or @@ -2366,6 +2271,128 @@ void CodeGenerator::Comparison(AstNode* node, } +void CodeGenerator::ConstantSmiComparison(Condition cc, + bool strict, + ControlDestination* dest, + Result* left_side, + Result* right_side, + bool left_side_constant_smi, + bool right_side_constant_smi, + bool is_loop_condition) { + if (left_side_constant_smi && right_side_constant_smi) { + // Trivial case, comparing two constants. + int left_value = Smi::cast(*left_side->handle())->value(); + int right_value = Smi::cast(*right_side->handle())->value(); + switch (cc) { + case less: + dest->Goto(left_value < right_value); + break; + case equal: + dest->Goto(left_value == right_value); + break; + case greater_equal: + dest->Goto(left_value >= right_value); + break; + default: + UNREACHABLE(); + } + } else { + // Only one side is a constant Smi. + // If left side is a constant Smi, reverse the operands. + // Since one side is a constant Smi, conversion order does not matter. + if (left_side_constant_smi) { + Result* temp = left_side; + left_side = right_side; + right_side = temp; + cc = ReverseCondition(cc); + // This may re-introduce greater or less_equal as the value of cc. + // CompareStub and the inline code both support all values of cc. + } + // Implement comparison against a constant Smi, inlining the case + // where both sides are Smis. + left_side->ToRegister(); + Register left_reg = left_side->reg(); + Smi* constant_smi = Smi::cast(*right_side->handle()); + + if (left_side->is_smi()) { + if (FLAG_debug_code) { + __ AbortIfNotSmi(left_reg); + } + // Test smi equality and comparison by signed int comparison. + // Both sides are smis, so we can use an Immediate. + __ SmiCompare(left_reg, constant_smi); + left_side->Unuse(); + right_side->Unuse(); + dest->Split(cc); + } else { + // Only the case where the left side could possibly be a non-smi is left. + JumpTarget is_smi; + if (cc == equal) { + // We can do the equality comparison before the smi check. + __ SmiCompare(left_reg, constant_smi); + dest->true_target()->Branch(equal); + Condition left_is_smi = masm_->CheckSmi(left_reg); + dest->false_target()->Branch(left_is_smi); + } else { + // Do the smi check, then the comparison. + Condition left_is_smi = masm_->CheckSmi(left_reg); + is_smi.Branch(left_is_smi, left_side, right_side); + } + + // Jump or fall through to here if we are comparing a non-smi to a + // constant smi. If the non-smi is a heap number and this is not + // a loop condition, inline the floating point code. + if (!is_loop_condition) { + // Right side is a constant smi and left side has been checked + // not to be a smi. + JumpTarget not_number; + __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), + Factory::heap_number_map()); + not_number.Branch(not_equal, left_side); + __ movsd(xmm1, + FieldOperand(left_reg, HeapNumber::kValueOffset)); + int value = constant_smi->value(); + if (value == 0) { + __ xorpd(xmm0, xmm0); + } else { + Result temp = allocator()->Allocate(); + __ movl(temp.reg(), Immediate(value)); + __ cvtlsi2sd(xmm0, temp.reg()); + temp.Unuse(); + } + __ ucomisd(xmm1, xmm0); + // Jump to builtin for NaN. + not_number.Branch(parity_even, left_side); + left_side->Unuse(); + dest->true_target()->Branch(DoubleCondition(cc)); + dest->false_target()->Jump(); + not_number.Bind(left_side); + } + + // Setup and call the compare stub. + CompareStub stub(cc, strict, kCantBothBeNaN); + Result result = frame_->CallStub(&stub, left_side, right_side); + result.ToRegister(); + __ testq(result.reg(), result.reg()); + result.Unuse(); + if (cc == equal) { + dest->Split(cc); + } else { + dest->true_target()->Branch(cc); + dest->false_target()->Jump(); + + // It is important for performance for this case to be at the end. + is_smi.Bind(left_side, right_side); + __ SmiCompare(left_reg, constant_smi); + left_side->Unuse(); + right_side->Unuse(); + dest->Split(cc); + } + } + } +} + + // Load a comparison operand into into a XMM register. Jump to not_numbers jump // target passing the left and right result if the operand is not a number. static void LoadComparisonOperand(MacroAssembler* masm_, diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h index b9a3b70..4e98a00 100644 --- a/src/x64/codegen-x64.h +++ b/src/x64/codegen-x64.h @@ -521,6 +521,17 @@ class CodeGenerator: public AstVisitor { Condition cc, bool strict, ControlDestination* destination); + + // If at least one of the sides is a constant smi, generate optimized code. + void ConstantSmiComparison(Condition cc, + bool strict, + ControlDestination* destination, + Result* left_side, + Result* right_side, + bool left_side_constant_smi, + bool right_side_constant_smi, + bool is_loop_condition); + void GenerateInlineNumberComparison(Result* left_side, Result* right_side, Condition cc,