Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 2897013: Avoid a smi check when comparing an unknown to a constant smi for equality on... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 2469 matching lines...) Expand 10 before | Expand all | Expand 10 after
2480 if (cc == greater || cc == less_equal) { 2480 if (cc == greater || cc == less_equal) {
2481 cc = ReverseCondition(cc); 2481 cc = ReverseCondition(cc);
2482 left_side = frame_->Pop(); 2482 left_side = frame_->Pop();
2483 right_side = frame_->Pop(); 2483 right_side = frame_->Pop();
2484 } else { 2484 } else {
2485 right_side = frame_->Pop(); 2485 right_side = frame_->Pop();
2486 left_side = frame_->Pop(); 2486 left_side = frame_->Pop();
2487 } 2487 }
2488 ASSERT(cc == less || cc == equal || cc == greater_equal); 2488 ASSERT(cc == less || cc == equal || cc == greater_equal);
2489 2489
2490 // If either side is a constant of some sort, we can probably optimize the 2490 // If either side is a constant smi, optimize the comparison.
2491 // comparison.
2492 bool left_side_constant_smi = false; 2491 bool left_side_constant_smi = false;
2493 bool left_side_constant_null = false; 2492 bool left_side_constant_null = false;
2494 bool left_side_constant_1_char_string = false; 2493 bool left_side_constant_1_char_string = false;
2495 if (left_side.is_constant()) { 2494 if (left_side.is_constant()) {
2496 left_side_constant_smi = left_side.handle()->IsSmi(); 2495 left_side_constant_smi = left_side.handle()->IsSmi();
2497 left_side_constant_null = left_side.handle()->IsNull(); 2496 left_side_constant_null = left_side.handle()->IsNull();
2498 left_side_constant_1_char_string = 2497 left_side_constant_1_char_string =
2499 (left_side.handle()->IsString() && 2498 (left_side.handle()->IsString() &&
2500 String::cast(*left_side.handle())->length() == 1 && 2499 String::cast(*left_side.handle())->length() == 1 &&
2501 String::cast(*left_side.handle())->IsAsciiRepresentation()); 2500 String::cast(*left_side.handle())->IsAsciiRepresentation());
2502 } 2501 }
2503 bool right_side_constant_smi = false; 2502 bool right_side_constant_smi = false;
2504 bool right_side_constant_null = false; 2503 bool right_side_constant_null = false;
2505 bool right_side_constant_1_char_string = false; 2504 bool right_side_constant_1_char_string = false;
2506 if (right_side.is_constant()) { 2505 if (right_side.is_constant()) {
2507 right_side_constant_smi = right_side.handle()->IsSmi(); 2506 right_side_constant_smi = right_side.handle()->IsSmi();
2508 right_side_constant_null = right_side.handle()->IsNull(); 2507 right_side_constant_null = right_side.handle()->IsNull();
2509 right_side_constant_1_char_string = 2508 right_side_constant_1_char_string =
2510 (right_side.handle()->IsString() && 2509 (right_side.handle()->IsString() &&
2511 String::cast(*right_side.handle())->length() == 1 && 2510 String::cast(*right_side.handle())->length() == 1 &&
2512 String::cast(*right_side.handle())->IsAsciiRepresentation()); 2511 String::cast(*right_side.handle())->IsAsciiRepresentation());
2513 } 2512 }
2514 2513
2515 if (left_side_constant_smi || right_side_constant_smi) { 2514 if (left_side_constant_smi || right_side_constant_smi) {
2516 if (left_side_constant_smi && right_side_constant_smi) { 2515 bool is_loop_condition = (node->AsExpression() != NULL) &&
2517 // Trivial case, comparing two constants. 2516 node->AsExpression()->is_loop_condition();
2518 int left_value = Smi::cast(*left_side.handle())->value(); 2517 ConstantSmiComparison(cc, strict, dest, &left_side, &right_side,
2519 int right_value = Smi::cast(*right_side.handle())->value(); 2518 left_side_constant_smi, right_side_constant_smi,
2520 switch (cc) { 2519 is_loop_condition);
2521 case less:
2522 dest->Goto(left_value < right_value);
2523 break;
2524 case equal:
2525 dest->Goto(left_value == right_value);
2526 break;
2527 case greater_equal:
2528 dest->Goto(left_value >= right_value);
2529 break;
2530 default:
2531 UNREACHABLE();
2532 }
2533 } else {
2534 // Only one side is a constant Smi.
2535 // If left side is a constant Smi, reverse the operands.
2536 // Since one side is a constant Smi, conversion order does not matter.
2537 if (left_side_constant_smi) {
2538 Result temp = left_side;
2539 left_side = right_side;
2540 right_side = temp;
2541 cc = ReverseCondition(cc);
2542 // This may re-introduce greater or less_equal as the value of cc.
2543 // CompareStub and the inline code both support all values of cc.
2544 }
2545 // Implement comparison against a constant Smi, inlining the case
2546 // where both sides are Smis.
2547 left_side.ToRegister();
2548 Register left_reg = left_side.reg();
2549 Handle<Object> right_val = right_side.handle();
2550
2551 // Here we split control flow to the stub call and inlined cases
2552 // before finally splitting it to the control destination. We use
2553 // a jump target and branching to duplicate the virtual frame at
2554 // the first split. We manually handle the off-frame references
2555 // by reconstituting them on the non-fall-through path.
2556
2557 if (left_side.is_smi()) {
2558 if (FLAG_debug_code) {
2559 __ AbortIfNotSmi(left_side.reg());
2560 }
2561 } else {
2562 JumpTarget is_smi;
2563 __ test(left_side.reg(), Immediate(kSmiTagMask));
2564 is_smi.Branch(zero, taken);
2565
2566 bool is_loop_condition = (node->AsExpression() != NULL) &&
2567 node->AsExpression()->is_loop_condition();
2568 if (!is_loop_condition &&
2569 CpuFeatures::IsSupported(SSE2) &&
2570 right_val->IsSmi()) {
2571 // Right side is a constant smi and left side has been checked
2572 // not to be a smi.
2573 CpuFeatures::Scope use_sse2(SSE2);
2574 JumpTarget not_number;
2575 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
2576 Immediate(Factory::heap_number_map()));
2577 not_number.Branch(not_equal, &left_side);
2578 __ movdbl(xmm1,
2579 FieldOperand(left_reg, HeapNumber::kValueOffset));
2580 int value = Smi::cast(*right_val)->value();
2581 if (value == 0) {
2582 __ xorpd(xmm0, xmm0);
2583 } else {
2584 Result temp = allocator()->Allocate();
2585 __ mov(temp.reg(), Immediate(value));
2586 __ cvtsi2sd(xmm0, Operand(temp.reg()));
2587 temp.Unuse();
2588 }
2589 __ ucomisd(xmm1, xmm0);
2590 // Jump to builtin for NaN.
2591 not_number.Branch(parity_even, &left_side);
2592 left_side.Unuse();
2593 dest->true_target()->Branch(DoubleCondition(cc));
2594 dest->false_target()->Jump();
2595 not_number.Bind(&left_side);
2596 }
2597
2598 // Setup and call the compare stub.
2599 CompareStub stub(cc, strict, kCantBothBeNaN);
2600 Result result = frame_->CallStub(&stub, &left_side, &right_side);
2601 result.ToRegister();
2602 __ cmp(result.reg(), 0);
2603 result.Unuse();
2604 dest->true_target()->Branch(cc);
2605 dest->false_target()->Jump();
2606
2607 is_smi.Bind();
2608 }
2609
2610 left_side = Result(left_reg);
2611 right_side = Result(right_val);
2612 // Test smi equality and comparison by signed int comparison.
2613 if (IsUnsafeSmi(right_side.handle())) {
2614 right_side.ToRegister();
2615 __ cmp(left_side.reg(), Operand(right_side.reg()));
2616 } else {
2617 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
2618 }
2619 left_side.Unuse();
2620 right_side.Unuse();
2621 dest->Split(cc);
2622 }
2623
2624 } else if (cc == equal && 2520 } else if (cc == equal &&
2625 (left_side_constant_null || right_side_constant_null)) { 2521 (left_side_constant_null || right_side_constant_null)) {
2626 // To make null checks efficient, we check if either the left side or 2522 // To make null checks efficient, we check if either the left side or
2627 // the right side is the constant 'null'. 2523 // the right side is the constant 'null'.
2628 // If so, we optimize the code by inlining a null check instead of 2524 // If so, we optimize the code by inlining a null check instead of
2629 // calling the (very) general runtime routine for checking equality. 2525 // calling the (very) general runtime routine for checking equality.
2630 Result operand = left_side_constant_null ? right_side : left_side; 2526 Result operand = left_side_constant_null ? right_side : left_side;
2631 right_side.Unuse(); 2527 right_side.Unuse();
2632 left_side.Unuse(); 2528 left_side.Unuse();
2633 operand.ToRegister(); 2529 operand.ToRegister();
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
2875 right_side = Result(right_reg); 2771 right_side = Result(right_reg);
2876 __ cmp(left_side.reg(), Operand(right_side.reg())); 2772 __ cmp(left_side.reg(), Operand(right_side.reg()));
2877 right_side.Unuse(); 2773 right_side.Unuse();
2878 left_side.Unuse(); 2774 left_side.Unuse();
2879 dest->Split(cc); 2775 dest->Split(cc);
2880 } 2776 }
2881 } 2777 }
2882 } 2778 }
2883 2779
2884 2780
2781 void CodeGenerator::ConstantSmiComparison(Condition cc,
2782 bool strict,
2783 ControlDestination* dest,
2784 Result* left_side,
2785 Result* right_side,
2786 bool left_side_constant_smi,
2787 bool right_side_constant_smi,
2788 bool is_loop_condition) {
2789 if (left_side_constant_smi && right_side_constant_smi) {
2790 // Trivial case, comparing two constants.
2791 int left_value = Smi::cast(*left_side->handle())->value();
2792 int right_value = Smi::cast(*right_side->handle())->value();
2793 switch (cc) {
2794 case less:
2795 dest->Goto(left_value < right_value);
2796 break;
2797 case equal:
2798 dest->Goto(left_value == right_value);
2799 break;
2800 case greater_equal:
2801 dest->Goto(left_value >= right_value);
2802 break;
2803 default:
2804 UNREACHABLE();
2805 }
2806 } else {
2807 // Only one side is a constant Smi.
2808 // If left side is a constant Smi, reverse the operands.
2809 // Since one side is a constant Smi, conversion order does not matter.
2810 if (left_side_constant_smi) {
2811 Result* temp = left_side;
2812 left_side = right_side;
2813 right_side = temp;
2814 cc = ReverseCondition(cc);
2815 // This may re-introduce greater or less_equal as the value of cc.
2816 // CompareStub and the inline code both support all values of cc.
2817 }
2818 // Implement comparison against a constant Smi, inlining the case
2819 // where both sides are Smis.
2820 left_side->ToRegister();
2821 Register left_reg = left_side->reg();
2822 Handle<Object> right_val = right_side->handle();
2823
2824 if (left_side->is_smi()) {
2825 if (FLAG_debug_code) {
2826 __ AbortIfNotSmi(left_reg);
2827 }
2828 // Test smi equality and comparison by signed int comparison.
2829 if (IsUnsafeSmi(right_side->handle())) {
2830 right_side->ToRegister();
2831 __ cmp(left_reg, Operand(right_side->reg()));
2832 } else {
2833 __ cmp(Operand(left_reg), Immediate(right_side->handle()));
2834 }
2835 left_side->Unuse();
2836 right_side->Unuse();
2837 dest->Split(cc);
2838 } else {
2839 // Only the case where the left side could possibly be a non-smi is left.
2840 JumpTarget is_smi;
2841 if (cc == equal) {
2842 // We can do the equality comparison before the smi check.
2843 __ cmp(Operand(left_reg), Immediate(right_side->handle()));
2844 dest->true_target()->Branch(equal);
2845 __ test(left_reg, Immediate(kSmiTagMask));
2846 dest->false_target()->Branch(zero);
2847 } else {
2848 // Do the smi check, then the comparison.
2849 JumpTarget is_not_smi;
2850 __ test(left_reg, Immediate(kSmiTagMask));
2851 is_smi.Branch(zero, left_side, right_side);
2852 }
2853
2854 // Jump or fall through to here if we are comparing a non-smi to a
2855 // constant smi. If the non-smi is a heap number and this is not
2856 // a loop condition, inline the floating point code.
2857 if (!is_loop_condition && CpuFeatures::IsSupported(SSE2)) {
2858 // Right side is a constant smi and left side has been checked
2859 // not to be a smi.
2860 CpuFeatures::Scope use_sse2(SSE2);
2861 JumpTarget not_number;
2862 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
2863 Immediate(Factory::heap_number_map()));
2864 not_number.Branch(not_equal, left_side);
2865 __ movdbl(xmm1,
2866 FieldOperand(left_reg, HeapNumber::kValueOffset));
2867 int value = Smi::cast(*right_val)->value();
2868 if (value == 0) {
2869 __ xorpd(xmm0, xmm0);
2870 } else {
2871 Result temp = allocator()->Allocate();
2872 __ mov(temp.reg(), Immediate(value));
2873 __ cvtsi2sd(xmm0, Operand(temp.reg()));
2874 temp.Unuse();
2875 }
2876 __ ucomisd(xmm1, xmm0);
2877 // Jump to builtin for NaN.
2878 not_number.Branch(parity_even, left_side);
2879 left_side->Unuse();
2880 dest->true_target()->Branch(DoubleCondition(cc));
2881 dest->false_target()->Jump();
2882 not_number.Bind(left_side);
2883 }
2884
2885 // Setup and call the compare stub.
2886 CompareStub stub(cc, strict, kCantBothBeNaN);
2887 Result result = frame_->CallStub(&stub, left_side, right_side);
2888 result.ToRegister();
2889 __ test(result.reg(), Operand(result.reg()));
2890 result.Unuse();
2891 if (cc == equal) {
2892 dest->Split(cc);
2893 } else {
2894 dest->true_target()->Branch(cc);
2895 dest->false_target()->Jump();
2896
2897 // It is important for performance for this case to be at the end.
2898 is_smi.Bind(left_side, right_side);
2899 if (IsUnsafeSmi(right_side->handle())) {
2900 right_side->ToRegister();
2901 __ cmp(left_reg, Operand(right_side->reg()));
2902 } else {
2903 __ cmp(Operand(left_reg), Immediate(right_side->handle()));
2904 }
2905 left_side->Unuse();
2906 right_side->Unuse();
2907 dest->Split(cc);
2908 }
2909 }
2910 }
2911 }
2912
2913
2885 // Check that the comparison operand is a number. Jump to not_numbers jump 2914 // Check that the comparison operand is a number. Jump to not_numbers jump
2886 // target passing the left and right result if the operand is not a number. 2915 // target passing the left and right result if the operand is not a number.
2887 static void CheckComparisonOperand(MacroAssembler* masm_, 2916 static void CheckComparisonOperand(MacroAssembler* masm_,
2888 Result* operand, 2917 Result* operand,
2889 Result* left_side, 2918 Result* left_side,
2890 Result* right_side, 2919 Result* right_side,
2891 JumpTarget* not_numbers) { 2920 JumpTarget* not_numbers) {
2892 // Perform check if operand is not known to be a number. 2921 // Perform check if operand is not known to be a number.
2893 if (!operand->type_info().IsNumber()) { 2922 if (!operand->type_info().IsNumber()) {
2894 Label done; 2923 Label done;
(...skipping 10860 matching lines...) Expand 10 before | Expand all | Expand 10 after
13755 masm.GetCode(&desc); 13784 masm.GetCode(&desc);
13756 // Call the function from C++. 13785 // Call the function from C++.
13757 return FUNCTION_CAST<MemCopyFunction>(buffer); 13786 return FUNCTION_CAST<MemCopyFunction>(buffer);
13758 } 13787 }
13759 13788
13760 #undef __ 13789 #undef __
13761 13790
13762 } } // namespace v8::internal 13791 } } // namespace v8::internal
13763 13792
13764 #endif // V8_TARGET_ARCH_IA32 13793 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698