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

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

Issue 1251009: Re-apply "Inline floating point compare"... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years, 9 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
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 893 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 enum ArgLocation { 904 enum ArgLocation {
905 ARGS_ON_STACK, 905 ARGS_ON_STACK,
906 ARGS_IN_REGISTERS 906 ARGS_IN_REGISTERS
907 }; 907 };
908 908
909 // Code pattern for loading a floating point value. Input value must 909 // Code pattern for loading a floating point value. Input value must
910 // be either a smi or a heap number object (fp value). Requirements: 910 // be either a smi or a heap number object (fp value). Requirements:
911 // operand in register number. Returns operand as floating point number 911 // operand in register number. Returns operand as floating point number
912 // on FPU stack. 912 // on FPU stack.
913 static void LoadFloatOperand(MacroAssembler* masm, Register number); 913 static void LoadFloatOperand(MacroAssembler* masm, Register number);
914
914 // Code pattern for loading floating point values. Input values must 915 // Code pattern for loading floating point values. Input values must
915 // be either smi or heap number objects (fp values). Requirements: 916 // be either smi or heap number objects (fp values). Requirements:
916 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. 917 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
917 // Returns operands as floating point numbers on FPU stack. 918 // Returns operands as floating point numbers on FPU stack.
918 static void LoadFloatOperands(MacroAssembler* masm, 919 static void LoadFloatOperands(MacroAssembler* masm,
919 Register scratch, 920 Register scratch,
920 ArgLocation arg_location = ARGS_ON_STACK); 921 ArgLocation arg_location = ARGS_ON_STACK);
921 922
922 // Similar to LoadFloatOperand but assumes that both operands are smis. 923 // Similar to LoadFloatOperand but assumes that both operands are smis.
923 // Expects operands in edx, eax. 924 // Expects operands in edx, eax.
924 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); 925 static void LoadFloatSmis(MacroAssembler* masm, Register scratch);
925 926
926 // Test if operands are smi or number objects (fp). Requirements: 927 // Test if operands are smi or number objects (fp). Requirements:
927 // operand_1 in eax, operand_2 in edx; falls through on float 928 // operand_1 in eax, operand_2 in edx; falls through on float
928 // operands, jumps to the non_float label otherwise. 929 // operands, jumps to the non_float label otherwise.
929 static void CheckFloatOperands(MacroAssembler* masm, 930 static void CheckFloatOperands(MacroAssembler* masm,
930 Label* non_float, 931 Label* non_float,
931 Register scratch); 932 Register scratch);
933
932 // Takes the operands in edx and eax and loads them as integers in eax 934 // Takes the operands in edx and eax and loads them as integers in eax
933 // and ecx. 935 // and ecx.
934 static void LoadAsIntegers(MacroAssembler* masm, 936 static void LoadAsIntegers(MacroAssembler* masm,
935 NumberInfo number_info, 937 NumberInfo number_info,
936 bool use_sse3, 938 bool use_sse3,
937 Label* operand_conversion_failure); 939 Label* operand_conversion_failure);
938 static void LoadNumbersAsIntegers(MacroAssembler* masm, 940 static void LoadNumbersAsIntegers(MacroAssembler* masm,
939 NumberInfo number_info, 941 NumberInfo number_info,
940 bool use_sse3, 942 bool use_sse3,
941 Label* operand_conversion_failure); 943 Label* operand_conversion_failure);
942 static void LoadUnknownsAsIntegers(MacroAssembler* masm, 944 static void LoadUnknownsAsIntegers(MacroAssembler* masm,
943 bool use_sse3, 945 bool use_sse3,
944 Label* operand_conversion_failure); 946 Label* operand_conversion_failure);
945 947
946 // Test if operands are smis or heap numbers and load them 948 // Test if operands are smis or heap numbers and load them
947 // into xmm0 and xmm1 if they are. Operands are in edx and eax. 949 // into xmm0 and xmm1 if they are. Operands are in edx and eax.
948 // Leaves operands unchanged. 950 // Leaves operands unchanged.
949 static void LoadSSE2Operands(MacroAssembler* masm); 951 static void LoadSSE2Operands(MacroAssembler* masm);
952
950 // Test if operands are numbers (smi or HeapNumber objects), and load 953 // Test if operands are numbers (smi or HeapNumber objects), and load
951 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 954 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if
952 // either operand is not a number. Operands are in edx and eax. 955 // either operand is not a number. Operands are in edx and eax.
953 // Leaves operands unchanged. 956 // Leaves operands unchanged.
954 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); 957 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
955 958
956 // Similar to LoadSSE2Operands but assumes that both operands are smis. 959 // Similar to LoadSSE2Operands but assumes that both operands are smis.
957 // Expects operands in edx, eax. 960 // Expects operands in edx, eax.
958 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); 961 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);
959 }; 962 };
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after
2354 2357
2355 static bool CouldBeNaN(const Result& result) { 2358 static bool CouldBeNaN(const Result& result) {
2356 if (result.number_info().IsSmi()) return false; 2359 if (result.number_info().IsSmi()) return false;
2357 if (result.number_info().IsInteger32()) return false; 2360 if (result.number_info().IsInteger32()) return false;
2358 if (!result.is_constant()) return true; 2361 if (!result.is_constant()) return true;
2359 if (!result.handle()->IsHeapNumber()) return false; 2362 if (!result.handle()->IsHeapNumber()) return false;
2360 return isnan(HeapNumber::cast(*result.handle())->value()); 2363 return isnan(HeapNumber::cast(*result.handle())->value());
2361 } 2364 }
2362 2365
2363 2366
2367 // Convert from signed to unsigned comparison to match the way EFLAGS are set
2368 // by FPU and XMM compare instructions.
2369 static Condition DoubleCondition(Condition cc) {
2370 switch (cc) {
2371 case less: return below;
2372 case equal: return equal;
2373 case less_equal: return below_equal;
2374 case greater: return above;
2375 case greater_equal: return above_equal;
2376 default: UNREACHABLE();
2377 }
2378 UNREACHABLE();
2379 return equal;
2380 }
2381
2382
2364 void CodeGenerator::Comparison(AstNode* node, 2383 void CodeGenerator::Comparison(AstNode* node,
2365 Condition cc, 2384 Condition cc,
2366 bool strict, 2385 bool strict,
2367 ControlDestination* dest) { 2386 ControlDestination* dest) {
2368 // Strict only makes sense for equality comparisons. 2387 // Strict only makes sense for equality comparisons.
2369 ASSERT(!strict || cc == equal); 2388 ASSERT(!strict || cc == equal);
2370 2389
2371 Result left_side; 2390 Result left_side;
2372 Result right_side; 2391 Result right_side;
2373 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 2392 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
2424 } 2443 }
2425 } else { 2444 } else {
2426 // Only one side is a constant Smi. 2445 // Only one side is a constant Smi.
2427 // If left side is a constant Smi, reverse the operands. 2446 // If left side is a constant Smi, reverse the operands.
2428 // Since one side is a constant Smi, conversion order does not matter. 2447 // Since one side is a constant Smi, conversion order does not matter.
2429 if (left_side_constant_smi) { 2448 if (left_side_constant_smi) {
2430 Result temp = left_side; 2449 Result temp = left_side;
2431 left_side = right_side; 2450 left_side = right_side;
2432 right_side = temp; 2451 right_side = temp;
2433 cc = ReverseCondition(cc); 2452 cc = ReverseCondition(cc);
2434 // This may reintroduce greater or less_equal as the value of cc. 2453 // This may re-introduce greater or less_equal as the value of cc.
2435 // CompareStub and the inline code both support all values of cc. 2454 // CompareStub and the inline code both support all values of cc.
2436 } 2455 }
2437 // Implement comparison against a constant Smi, inlining the case 2456 // Implement comparison against a constant Smi, inlining the case
2438 // where both sides are Smis. 2457 // where both sides are Smis.
2439 left_side.ToRegister(); 2458 left_side.ToRegister();
2440 Register left_reg = left_side.reg(); 2459 Register left_reg = left_side.reg();
2441 Handle<Object> right_val = right_side.handle(); 2460 Handle<Object> right_val = right_side.handle();
2442 2461
2443 // Here we split control flow to the stub call and inlined cases 2462 // Here we split control flow to the stub call and inlined cases
2444 // before finally splitting it to the control destination. We use 2463 // before finally splitting it to the control destination. We use
(...skipping 28 matching lines...) Expand all
2473 } else { 2492 } else {
2474 Result temp = allocator()->Allocate(); 2493 Result temp = allocator()->Allocate();
2475 __ mov(temp.reg(), Immediate(value)); 2494 __ mov(temp.reg(), Immediate(value));
2476 __ cvtsi2sd(xmm0, Operand(temp.reg())); 2495 __ cvtsi2sd(xmm0, Operand(temp.reg()));
2477 temp.Unuse(); 2496 temp.Unuse();
2478 } 2497 }
2479 __ comisd(xmm1, xmm0); 2498 __ comisd(xmm1, xmm0);
2480 // Jump to builtin for NaN. 2499 // Jump to builtin for NaN.
2481 not_number.Branch(parity_even, &left_side); 2500 not_number.Branch(parity_even, &left_side);
2482 left_side.Unuse(); 2501 left_side.Unuse();
2483 Condition double_cc = cc; 2502 dest->true_target()->Branch(DoubleCondition(cc));
2484 switch (cc) {
2485 case less: double_cc = below; break;
2486 case equal: double_cc = equal; break;
2487 case less_equal: double_cc = below_equal; break;
2488 case greater: double_cc = above; break;
2489 case greater_equal: double_cc = above_equal; break;
2490 default: UNREACHABLE();
2491 }
2492 dest->true_target()->Branch(double_cc);
2493 dest->false_target()->Jump(); 2503 dest->false_target()->Jump();
2494 not_number.Bind(&left_side); 2504 not_number.Bind(&left_side);
2495 } 2505 }
2496 2506
2497 // Setup and call the compare stub. 2507 // Setup and call the compare stub.
2498 CompareStub stub(cc, strict, kCantBothBeNaN); 2508 CompareStub stub(cc, strict, kCantBothBeNaN);
2499 Result result = frame_->CallStub(&stub, &left_side, &right_side); 2509 Result result = frame_->CallStub(&stub, &left_side, &right_side);
2500 result.ToRegister(); 2510 result.ToRegister();
2501 __ cmp(result.reg(), 0); 2511 __ cmp(result.reg(), 0);
2502 result.Unuse(); 2512 result.Unuse();
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
2681 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), 2691 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset),
2682 Immediate(1)); 2692 Immediate(1));
2683 __ bind(&characters_were_different); 2693 __ bind(&characters_were_different);
2684 } 2694 }
2685 temp2.Unuse(); 2695 temp2.Unuse();
2686 left_side.Unuse(); 2696 left_side.Unuse();
2687 right_side.Unuse(); 2697 right_side.Unuse();
2688 dest->Split(cc); 2698 dest->Split(cc);
2689 } 2699 }
2690 } else { 2700 } else {
2691 // Neither side is a constant Smi or null. 2701 // Neither side is a constant Smi, constant 1-char string or constant null.
2692 // If either side is a non-smi constant, skip the smi check. 2702 // If either side is a non-smi constant, or known to be a heap number skip
2703 // the smi check.
2693 bool known_non_smi = 2704 bool known_non_smi =
2694 (left_side.is_constant() && !left_side.handle()->IsSmi()) || 2705 (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
2695 (right_side.is_constant() && !right_side.handle()->IsSmi()); 2706 (right_side.is_constant() && !right_side.handle()->IsSmi()) ||
2707 left_side.number_info().IsDouble() ||
2708 right_side.number_info().IsDouble();
2696 NaNInformation nan_info = 2709 NaNInformation nan_info =
2697 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? 2710 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
2698 kBothCouldBeNaN : 2711 kBothCouldBeNaN :
2699 kCantBothBeNaN; 2712 kCantBothBeNaN;
2713
2714 // Inline number comparison handling any combination of smi's and heap
2715 // numbers if:
2716 // code is in a loop
2717 // the compare operation is different from equal
2718 // compare is not a for-loop comparison
2719 // The reason for excluding equal is that it will most likely be done
2720 // with smi's (not heap numbers) and the code to comparing smi's is inlined
2721 // separately. The same reason applies for for-loop comparison which will
2722 // also most likely be smi comparisons.
2723 bool is_loop_condition = (node->AsExpression() != NULL)
2724 && node->AsExpression()->is_loop_condition();
2725 bool inline_number_compare =
2726 loop_nesting() > 0 && cc != equal && !is_loop_condition;
2727
2728 // Left and right needed in registers for the following code.
2700 left_side.ToRegister(); 2729 left_side.ToRegister();
2701 right_side.ToRegister(); 2730 right_side.ToRegister();
2702 2731
2703 if (known_non_smi) { 2732 if (known_non_smi) {
2704 // When non-smi, call out to the compare stub. 2733 // Inline the equality check if both operands can't be a NaN. If both
2705 CompareStub stub(cc, strict, nan_info); 2734 // objects are the same they are equal.
2735 if (nan_info == kCantBothBeNaN && cc == equal) {
2736 __ cmp(left_side.reg(), Operand(right_side.reg()));
2737 dest->true_target()->Branch(equal);
2738 }
2739
2740 // Inline number comparison.
2741 if (inline_number_compare) {
2742 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
2743 }
2744
2745 // End of in-line compare, call out to the compare stub. Don't include
2746 // number comparison in the stub if it was inlined.
2747 CompareStub stub(cc, strict, nan_info, !inline_number_compare);
2706 Result answer = frame_->CallStub(&stub, &left_side, &right_side); 2748 Result answer = frame_->CallStub(&stub, &left_side, &right_side);
2707 if (cc == equal) { 2749 if (cc == equal) {
2708 __ test(answer.reg(), Operand(answer.reg())); 2750 __ test(answer.reg(), Operand(answer.reg()));
2709 } else { 2751 } else {
2710 __ cmp(answer.reg(), 0); 2752 __ cmp(answer.reg(), 0);
2711 } 2753 }
2712 answer.Unuse(); 2754 answer.Unuse();
2713 dest->Split(cc); 2755 dest->Split(cc);
2714 } else { 2756 } else {
2715 // Here we split control flow to the stub call and inlined cases 2757 // Here we split control flow to the stub call and inlined cases
2716 // before finally splitting it to the control destination. We use 2758 // before finally splitting it to the control destination. We use
2717 // a jump target and branching to duplicate the virtual frame at 2759 // a jump target and branching to duplicate the virtual frame at
2718 // the first split. We manually handle the off-frame references 2760 // the first split. We manually handle the off-frame references
2719 // by reconstituting them on the non-fall-through path. 2761 // by reconstituting them on the non-fall-through path.
2720 JumpTarget is_smi; 2762 JumpTarget is_smi;
2721 Register left_reg = left_side.reg(); 2763 Register left_reg = left_side.reg();
2722 Register right_reg = right_side.reg(); 2764 Register right_reg = right_side.reg();
2723 2765
2766 // In-line check for comparing two smis.
2724 Result temp = allocator_->Allocate(); 2767 Result temp = allocator_->Allocate();
2725 ASSERT(temp.is_valid()); 2768 ASSERT(temp.is_valid());
2726 __ mov(temp.reg(), left_side.reg()); 2769 __ mov(temp.reg(), left_side.reg());
2727 __ or_(temp.reg(), Operand(right_side.reg())); 2770 __ or_(temp.reg(), Operand(right_side.reg()));
2728 __ test(temp.reg(), Immediate(kSmiTagMask)); 2771 __ test(temp.reg(), Immediate(kSmiTagMask));
2729 temp.Unuse(); 2772 temp.Unuse();
2730 is_smi.Branch(zero, taken); 2773 is_smi.Branch(zero, taken);
2731 // When non-smi, call out to the compare stub. 2774
2732 CompareStub stub(cc, strict, nan_info); 2775 // Inline the equality check if both operands can't be a NaN. If both
2776 // objects are the same they are equal.
2777 if (nan_info == kCantBothBeNaN && cc == equal) {
2778 __ cmp(left_side.reg(), Operand(right_side.reg()));
2779 dest->true_target()->Branch(equal);
2780 }
2781
2782 // Inline number comparison.
2783 if (inline_number_compare) {
2784 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
2785 }
2786
2787 // End of in-line compare, call out to the compare stub. Don't include
2788 // number comparison in the stub if it was inlined.
2789 CompareStub stub(cc, strict, nan_info, !inline_number_compare);
2733 Result answer = frame_->CallStub(&stub, &left_side, &right_side); 2790 Result answer = frame_->CallStub(&stub, &left_side, &right_side);
2734 if (cc == equal) { 2791 if (cc == equal) {
2735 __ test(answer.reg(), Operand(answer.reg())); 2792 __ test(answer.reg(), Operand(answer.reg()));
2736 } else { 2793 } else {
2737 __ cmp(answer.reg(), 0); 2794 __ cmp(answer.reg(), 0);
2738 } 2795 }
2739 answer.Unuse(); 2796 answer.Unuse();
2740 dest->true_target()->Branch(cc); 2797 dest->true_target()->Branch(cc);
2741 dest->false_target()->Jump(); 2798 dest->false_target()->Jump();
2742 2799
2743 is_smi.Bind(); 2800 is_smi.Bind();
2744 left_side = Result(left_reg); 2801 left_side = Result(left_reg);
2745 right_side = Result(right_reg); 2802 right_side = Result(right_reg);
2746 __ cmp(left_side.reg(), Operand(right_side.reg())); 2803 __ cmp(left_side.reg(), Operand(right_side.reg()));
2747 right_side.Unuse(); 2804 right_side.Unuse();
2748 left_side.Unuse(); 2805 left_side.Unuse();
2749 dest->Split(cc); 2806 dest->Split(cc);
2750 } 2807 }
2751 } 2808 }
2752 } 2809 }
2753 2810
2754 2811
2812 // Check that the comparison operand is a number. Jump to not_numbers jump
2813 // target passing the left and right result if the operand is not a number.
2814 static void CheckComparisonOperand(MacroAssembler* masm_,
2815 Result* operand,
2816 Result* left_side,
2817 Result* right_side,
2818 JumpTarget* not_numbers) {
2819 // Perform check if operand is not known to be a number.
2820 if (!operand->number_info().IsNumber()) {
2821 Label done;
2822 __ test(operand->reg(), Immediate(kSmiTagMask));
2823 __ j(zero, &done);
2824 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
2825 Immediate(Factory::heap_number_map()));
2826 not_numbers->Branch(not_equal, left_side, right_side, not_taken);
2827 __ bind(&done);
2828 }
2829 }
2830
2831
2832 // Load a comparison operand to the FPU stack. This assumes that the operand has
2833 // already been checked and is a number.
2834 static void LoadComparisonOperand(MacroAssembler* masm_,
2835 Result* operand) {
2836 Label done;
2837 if (operand->number_info().IsDouble()) {
2838 // Operand is known to be a heap number, just load it.
2839 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
2840 } else if (operand->number_info().IsSmi()) {
2841 // Operand is known to be a smi. Convert it to double and keep the original
2842 // smi.
2843 __ SmiUntag(operand->reg());
2844 __ push(operand->reg());
2845 __ fild_s(Operand(esp, 0));
2846 __ pop(operand->reg());
2847 __ SmiTag(operand->reg());
2848 } else {
2849 // Operand type not known, check for smi otherwise assume heap number.
2850 Label smi;
2851 __ test(operand->reg(), Immediate(kSmiTagMask));
2852 __ j(zero, &smi);
2853 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
2854 __ jmp(&done);
2855 __ bind(&smi);
2856 __ SmiUntag(operand->reg());
2857 __ push(operand->reg());
2858 __ fild_s(Operand(esp, 0));
2859 __ pop(operand->reg());
2860 __ SmiTag(operand->reg());
2861 __ jmp(&done);
2862 }
2863 __ bind(&done);
2864 }
2865
2866
2867 // Load a comparison operand into into a XMM register. Jump to not_numbers jump
2868 // target passing the left and right result if the operand is not a number.
2869 static void LoadComparisonOperandSSE2(MacroAssembler* masm_,
2870 Result* operand,
2871 XMMRegister reg,
2872 Result* left_side,
2873 Result* right_side,
2874 JumpTarget* not_numbers) {
2875 Label done;
2876 if (operand->number_info().IsDouble()) {
2877 // Operand is known to be a heap number, just load it.
2878 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
2879 } else if (operand->number_info().IsSmi()) {
2880 // Operand is known to be a smi. Convert it to double and keep the original
2881 // smi.
2882 __ SmiUntag(operand->reg());
2883 __ cvtsi2sd(reg, Operand(operand->reg()));
2884 __ SmiTag(operand->reg());
2885 } else {
2886 // Operand type not known, check for smi or heap number.
2887 Label smi;
2888 __ test(operand->reg(), Immediate(kSmiTagMask));
2889 __ j(zero, &smi);
2890 if (!operand->number_info().IsNumber()) {
2891 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
2892 Immediate(Factory::heap_number_map()));
2893 not_numbers->Branch(not_equal, left_side, right_side, taken);
2894 }
2895 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
2896 __ jmp(&done);
2897
2898 __ bind(&smi);
2899 // Comvert smi to float and keep the original smi.
2900 __ SmiUntag(operand->reg());
2901 __ cvtsi2sd(reg, Operand(operand->reg()));
2902 __ SmiTag(operand->reg());
2903 __ jmp(&done);
2904 }
2905 __ bind(&done);
2906 }
2907
2908
2909 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side,
2910 Result* right_side,
2911 Condition cc,
2912 ControlDestination* dest) {
2913 ASSERT(left_side->is_register());
2914 ASSERT(right_side->is_register());
2915
2916 JumpTarget not_numbers;
2917 if (CpuFeatures::IsSupported(SSE2)) {
2918 CpuFeatures::Scope use_sse2(SSE2);
2919
2920 // Load left and right operand into registers xmm0 and xmm1 and compare.
2921 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side,
2922 &not_numbers);
2923 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side,
2924 &not_numbers);
2925 __ comisd(xmm0, xmm1);
2926 } else {
2927 Label check_right, compare;
2928
2929 // Make sure that both comparison operands are numbers.
2930 CheckComparisonOperand(masm_, left_side, left_side, right_side,
2931 &not_numbers);
2932 CheckComparisonOperand(masm_, right_side, left_side, right_side,
2933 &not_numbers);
2934
2935 // Load right and left operand to FPU stack and compare.
2936 LoadComparisonOperand(masm_, right_side);
2937 LoadComparisonOperand(masm_, left_side);
2938 __ FCmp();
2939 }
2940
2941 // Bail out if a NaN is involved.
2942 not_numbers.Branch(parity_even, left_side, right_side, not_taken);
2943
2944 // Split to destination targets based on comparison.
2945 left_side->Unuse();
2946 right_side->Unuse();
2947 dest->true_target()->Branch(DoubleCondition(cc));
2948 dest->false_target()->Jump();
2949
2950 not_numbers.Bind(left_side, right_side);
2951 }
2952
2953
2755 // Call the function just below TOS on the stack with the given 2954 // Call the function just below TOS on the stack with the given
2756 // arguments. The receiver is the TOS. 2955 // arguments. The receiver is the TOS.
2757 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, 2956 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
2758 CallFunctionFlags flags, 2957 CallFunctionFlags flags,
2759 int position) { 2958 int position) {
2760 // Push the arguments ("left-to-right") on the stack. 2959 // Push the arguments ("left-to-right") on the stack.
2761 int arg_count = args->length(); 2960 int arg_count = args->length();
2762 for (int i = 0; i < arg_count; i++) { 2961 for (int i = 0; i < arg_count; i++) {
2763 Load(args->at(i)); 2962 Load(args->at(i));
2764 } 2963 }
(...skipping 8105 matching lines...) Expand 10 before | Expand all | Expand 10 after
10870 } 11069 }
10871 __ bind(&slow); 11070 __ bind(&slow);
10872 } 11071 }
10873 11072
10874 // Push arguments below the return address. 11073 // Push arguments below the return address.
10875 __ pop(ecx); 11074 __ pop(ecx);
10876 __ push(eax); 11075 __ push(eax);
10877 __ push(edx); 11076 __ push(edx);
10878 __ push(ecx); 11077 __ push(ecx);
10879 11078
10880 // Inlined floating point compare. 11079 // Generate the number comparison code.
10881 // Call builtin if operands are not floating point or smi. 11080 if (include_number_compare_) {
10882 Label check_for_symbols; 11081 Label non_number_comparison;
10883 Label unordered; 11082 Label unordered;
10884 if (CpuFeatures::IsSupported(SSE2)) { 11083 if (CpuFeatures::IsSupported(SSE2)) {
10885 CpuFeatures::Scope use_sse2(SSE2); 11084 CpuFeatures::Scope use_sse2(SSE2);
10886 CpuFeatures::Scope use_cmov(CMOV); 11085 CpuFeatures::Scope use_cmov(CMOV);
10887 11086
10888 FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols); 11087 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
10889 __ comisd(xmm0, xmm1); 11088 __ comisd(xmm0, xmm1);
10890 11089
10891 // Jump to builtin for NaN. 11090 // Don't base result on EFLAGS when a NaN is involved.
10892 __ j(parity_even, &unordered, not_taken); 11091 __ j(parity_even, &unordered, not_taken);
10893 __ mov(eax, 0); // equal 11092 // Return a result of -1, 0, or 1, based on EFLAGS.
10894 __ mov(ecx, Immediate(Smi::FromInt(1))); 11093 __ mov(eax, 0); // equal
10895 __ cmov(above, eax, Operand(ecx)); 11094 __ mov(ecx, Immediate(Smi::FromInt(1)));
10896 __ mov(ecx, Immediate(Smi::FromInt(-1))); 11095 __ cmov(above, eax, Operand(ecx));
10897 __ cmov(below, eax, Operand(ecx)); 11096 __ mov(ecx, Immediate(Smi::FromInt(-1)));
10898 __ ret(2 * kPointerSize); 11097 __ cmov(below, eax, Operand(ecx));
10899 } else { 11098 __ ret(2 * kPointerSize);
10900 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); 11099 } else {
10901 FloatingPointHelper::LoadFloatOperands(masm, ecx); 11100 FloatingPointHelper::CheckFloatOperands(
10902 __ FCmp(); 11101 masm, &non_number_comparison, ebx);
11102 FloatingPointHelper::LoadFloatOperands(masm, ecx);
11103 __ FCmp();
10903 11104
10904 // Jump to builtin for NaN. 11105 // Don't base result on EFLAGS when a NaN is involved.
10905 __ j(parity_even, &unordered, not_taken); 11106 __ j(parity_even, &unordered, not_taken);
10906 11107
10907 Label below_lbl, above_lbl; 11108 Label below_label, above_label;
10908 // Return a result of -1, 0, or 1, to indicate result of comparison. 11109 // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove
10909 __ j(below, &below_lbl, not_taken); 11110 // two arguments from the stack as they have been pushed in preparation
10910 __ j(above, &above_lbl, not_taken); 11111 // of a possible runtime call.
11112 __ j(below, &below_label, not_taken);
11113 __ j(above, &above_label, not_taken);
10911 11114
10912 __ xor_(eax, Operand(eax)); // equal 11115 __ xor_(eax, Operand(eax));
10913 // Both arguments were pushed in case a runtime call was needed. 11116 __ ret(2 * kPointerSize);
10914 __ ret(2 * kPointerSize);
10915 11117
10916 __ bind(&below_lbl); 11118 __ bind(&below_label);
10917 __ mov(eax, Immediate(Smi::FromInt(-1))); 11119 __ mov(eax, Immediate(Smi::FromInt(-1)));
10918 __ ret(2 * kPointerSize); 11120 __ ret(2 * kPointerSize);
10919 11121
10920 __ bind(&above_lbl); 11122 __ bind(&above_label);
10921 __ mov(eax, Immediate(Smi::FromInt(1))); 11123 __ mov(eax, Immediate(Smi::FromInt(1)));
11124 __ ret(2 * kPointerSize);
11125 }
11126
11127 // If one of the numbers was NaN, then the result is always false.
11128 // The cc is never not-equal.
11129 __ bind(&unordered);
11130 ASSERT(cc_ != not_equal);
11131 if (cc_ == less || cc_ == less_equal) {
11132 __ mov(eax, Immediate(Smi::FromInt(1)));
11133 } else {
11134 __ mov(eax, Immediate(Smi::FromInt(-1)));
11135 }
10922 __ ret(2 * kPointerSize); // eax, edx were pushed 11136 __ ret(2 * kPointerSize); // eax, edx were pushed
11137
11138 // The number comparison code did not provide a valid result.
11139 __ bind(&non_number_comparison);
10923 } 11140 }
10924 // If one of the numbers was NaN, then the result is always false.
10925 // The cc is never not-equal.
10926 __ bind(&unordered);
10927 ASSERT(cc_ != not_equal);
10928 if (cc_ == less || cc_ == less_equal) {
10929 __ mov(eax, Immediate(Smi::FromInt(1)));
10930 } else {
10931 __ mov(eax, Immediate(Smi::FromInt(-1)));
10932 }
10933 __ ret(2 * kPointerSize); // eax, edx were pushed
10934 11141
10935 // Fast negative check for symbol-to-symbol equality. 11142 // Fast negative check for symbol-to-symbol equality.
10936 __ bind(&check_for_symbols);
10937 Label check_for_strings; 11143 Label check_for_strings;
10938 if (cc_ == equal) { 11144 if (cc_ == equal) {
10939 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 11145 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
10940 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); 11146 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
10941 11147
10942 // We've already checked for object identity, so if both operands 11148 // We've already checked for object identity, so if both operands
10943 // are symbols they aren't equal. Register eax already holds a 11149 // are symbols they aren't equal. Register eax already holds a
10944 // non-zero value, which indicates not equal, so just return. 11150 // non-zero value, which indicates not equal, so just return.
10945 __ ret(2 * kPointerSize); 11151 __ ret(2 * kPointerSize);
10946 } 11152 }
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
11536 __ bind(&is_not_instance); 11742 __ bind(&is_not_instance);
11537 __ Set(eax, Immediate(Smi::FromInt(1))); 11743 __ Set(eax, Immediate(Smi::FromInt(1)));
11538 __ ret(2 * kPointerSize); 11744 __ ret(2 * kPointerSize);
11539 11745
11540 // Slow-case: Go through the JavaScript implementation. 11746 // Slow-case: Go through the JavaScript implementation.
11541 __ bind(&slow); 11747 __ bind(&slow);
11542 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 11748 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
11543 } 11749 }
11544 11750
11545 11751
11546 // Unfortunately you have to run without snapshots to see most of these
11547 // names in the profile since most compare stubs end up in the snapshot.
11548 const char* CompareStub::GetName() {
11549 switch (cc_) {
11550 case less: return "CompareStub_LT";
11551 case greater: return "CompareStub_GT";
11552 case less_equal: return "CompareStub_LE";
11553 case greater_equal: return "CompareStub_GE";
11554 case not_equal: {
11555 if (strict_) {
11556 if (never_nan_nan_) {
11557 return "CompareStub_NE_STRICT_NO_NAN";
11558 } else {
11559 return "CompareStub_NE_STRICT";
11560 }
11561 } else {
11562 if (never_nan_nan_) {
11563 return "CompareStub_NE_NO_NAN";
11564 } else {
11565 return "CompareStub_NE";
11566 }
11567 }
11568 }
11569 case equal: {
11570 if (strict_) {
11571 if (never_nan_nan_) {
11572 return "CompareStub_EQ_STRICT_NO_NAN";
11573 } else {
11574 return "CompareStub_EQ_STRICT";
11575 }
11576 } else {
11577 if (never_nan_nan_) {
11578 return "CompareStub_EQ_NO_NAN";
11579 } else {
11580 return "CompareStub_EQ";
11581 }
11582 }
11583 }
11584 default: return "CompareStub";
11585 }
11586 }
11587
11588
11589 int CompareStub::MinorKey() { 11752 int CompareStub::MinorKey() {
11590 // Encode the three parameters in a unique 16 bit value. To avoid duplicate 11753 // Encode the three parameters in a unique 16 bit value. To avoid duplicate
11591 // stubs the never NaN NaN condition is only taken into account if the 11754 // stubs the never NaN NaN condition is only taken into account if the
11592 // condition is equals. 11755 // condition is equals.
11593 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); 11756 ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
11594 return ConditionField::encode(static_cast<unsigned>(cc_)) 11757 return ConditionField::encode(static_cast<unsigned>(cc_))
11595 | StrictField::encode(strict_) 11758 | StrictField::encode(strict_)
11596 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false); 11759 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
11760 | IncludeNumberCompareField::encode(include_number_compare_);
11597 } 11761 }
11598 11762
11599 11763
11764 // Unfortunately you have to run without snapshots to see most of these
11765 // names in the profile since most compare stubs end up in the snapshot.
11766 const char* CompareStub::GetName() {
11767 if (name_ != NULL) return name_;
11768 const int kMaxNameLength = 100;
11769 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
11770 if (name_ == NULL) return "OOM";
11771
11772 const char* cc_name;
11773 switch (cc_) {
11774 case less: cc_name = "LT"; break;
11775 case greater: cc_name = "GT"; break;
11776 case less_equal: cc_name = "LE"; break;
11777 case greater_equal: cc_name = "GE"; break;
11778 case equal: cc_name = "EQ"; break;
11779 case not_equal: cc_name = "NE"; break;
11780 default: cc_name = "UnknownCondition"; break;
11781 }
11782
11783 const char* strict_name = "";
11784 if (strict_ && (cc_ == equal || cc_ == not_equal)) {
11785 strict_name = "_STRICT";
11786 }
11787
11788 const char* never_nan_nan_name = "";
11789 if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) {
11790 never_nan_nan_name = "_NO_NAN";
11791 }
11792
11793 const char* include_number_compare_name = "";
11794 if (!include_number_compare_) {
11795 include_number_compare_name = "_NO_NUMBER";
11796 }
11797
11798 OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
11799 "CompareStub_%s%s%s%s",
11800 cc_name,
11801 strict_name,
11802 never_nan_nan_name,
11803 include_number_compare_name);
11804 return name_;
11805 }
11806
11807
11600 void StringAddStub::Generate(MacroAssembler* masm) { 11808 void StringAddStub::Generate(MacroAssembler* masm) {
11601 Label string_add_runtime; 11809 Label string_add_runtime;
11602 11810
11603 // Load the two arguments. 11811 // Load the two arguments.
11604 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 11812 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
11605 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 11813 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
11606 11814
11607 // Make sure that both arguments are strings if not known in advance. 11815 // Make sure that both arguments are strings if not known in advance.
11608 if (string_check_) { 11816 if (string_check_) {
11609 __ test(eax, Immediate(kSmiTagMask)); 11817 __ test(eax, Immediate(kSmiTagMask));
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after
12220 12428
12221 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 12429 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
12222 Register left, 12430 Register left,
12223 Register right, 12431 Register right,
12224 Register scratch1, 12432 Register scratch1,
12225 Register scratch2, 12433 Register scratch2,
12226 Register scratch3) { 12434 Register scratch3) {
12227 Label result_not_equal; 12435 Label result_not_equal;
12228 Label result_greater; 12436 Label result_greater;
12229 Label compare_lengths; 12437 Label compare_lengths;
12438
12439 __ IncrementCounter(&Counters::string_compare_native, 1);
12440
12230 // Find minimum length. 12441 // Find minimum length.
12231 Label left_shorter; 12442 Label left_shorter;
12232 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 12443 __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
12233 __ mov(scratch3, scratch1); 12444 __ mov(scratch3, scratch1);
12234 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 12445 __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
12235 12446
12236 Register length_delta = scratch3; 12447 Register length_delta = scratch3;
12237 12448
12238 __ j(less_equal, &left_shorter); 12449 __ j(less_equal, &left_shorter);
12239 // Right string is shorter. Change scratch1 to be length of right string. 12450 // Right string is shorter. Change scratch1 to be length of right string.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
12317 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 12528 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
12318 __ IncrementCounter(&Counters::string_compare_native, 1); 12529 __ IncrementCounter(&Counters::string_compare_native, 1);
12319 __ ret(2 * kPointerSize); 12530 __ ret(2 * kPointerSize);
12320 12531
12321 __ bind(&not_same); 12532 __ bind(&not_same);
12322 12533
12323 // Check that both objects are sequential ascii strings. 12534 // Check that both objects are sequential ascii strings.
12324 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 12535 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
12325 12536
12326 // Compare flat ascii strings. 12537 // Compare flat ascii strings.
12327 __ IncrementCounter(&Counters::string_compare_native, 1);
12328 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 12538 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
12329 12539
12330 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 12540 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
12331 // tagged as a small integer. 12541 // tagged as a small integer.
12332 __ bind(&runtime); 12542 __ bind(&runtime);
12333 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 12543 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
12334 } 12544 }
12335 12545
12336 #undef __ 12546 #undef __
12337 12547
12338 } } // namespace v8::internal 12548 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698