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

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

Issue 146081: X64: Implemented LikelySmiBinaryOperation (Closed)
Patch Set: Created 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 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 19 matching lines...) Expand all
30 30
31 #include "v8.h" 31 #include "v8.h"
32 32
33 #include "bootstrapper.h" 33 #include "bootstrapper.h"
34 #include "codegen-inl.h" 34 #include "codegen-inl.h"
35 #include "debug.h" 35 #include "debug.h"
36 #include "ic-inl.h" 36 #include "ic-inl.h"
37 #include "parser.h" 37 #include "parser.h"
38 #include "register-allocator-inl.h" 38 #include "register-allocator-inl.h"
39 #include "scopes.h" 39 #include "scopes.h"
40 #include "macro-assembler.h"
William Hesse 2009/06/24 11:39:35 Surely this was already included through a depende
40 41
41 // TODO(X64): Remove compiler.h when compiler test is removed. 42 // TODO(X64): Remove compiler.h when compiler test is removed.
42 #include "compiler.h" 43 #include "compiler.h"
43 44
44 namespace v8 { 45 namespace v8 {
45 namespace internal { 46 namespace internal {
46 47
47 #define __ ACCESS_MASM(masm_) 48 #define __ ACCESS_MASM(masm_)
48 49
49 // ------------------------------------------------------------------------- 50 // -------------------------------------------------------------------------
(...skipping 1279 matching lines...) Expand 10 before | Expand all | Expand 10 after
1329 // Use global object as receiver. 1330 // Use global object as receiver.
1330 LoadGlobalReceiver(); 1331 LoadGlobalReceiver();
1331 } else { 1332 } else {
1332 // The reference's size is non-negative. 1333 // The reference's size is non-negative.
1333 frame_->PushElementAt(ref.size()); 1334 frame_->PushElementAt(ref.size());
1334 } 1335 }
1335 1336
1336 // Call the function. 1337 // Call the function.
1337 CallWithArguments(args, node->position()); 1338 CallWithArguments(args, node->position());
1338 } 1339 }
1339
1340 } else { 1340 } else {
1341 // ---------------------------------- 1341 // ----------------------------------
1342 // JavaScript example: 'foo(1, 2, 3)' // foo is not global 1342 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
1343 // ---------------------------------- 1343 // ----------------------------------
1344 1344
1345 // Load the function. 1345 // Load the function.
1346 Load(function); 1346 Load(function);
1347 1347
1348 // Pass the global proxy as the receiver. 1348 // Pass the global proxy as the receiver.
1349 LoadGlobalReceiver(); 1349 LoadGlobalReceiver();
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1397 } 1397 }
1398 1398
1399 ZoneList<Expression*>* args = node->arguments(); 1399 ZoneList<Expression*>* args = node->arguments();
1400 Comment cmnt(masm_, "[ CallRuntime"); 1400 Comment cmnt(masm_, "[ CallRuntime");
1401 Runtime::Function* function = node->function(); 1401 Runtime::Function* function = node->function();
1402 1402
1403 if (function == NULL) { 1403 if (function == NULL) {
1404 // Prepare stack for calling JS runtime function. 1404 // Prepare stack for calling JS runtime function.
1405 frame_->Push(node->name()); 1405 frame_->Push(node->name());
1406 // Push the builtins object found in the current global object. 1406 // Push the builtins object found in the current global object.
1407 Result temp = allocator()->Allocate(); 1407 __ movq(kScratchRegister, GlobalObject());
1408 ASSERT(temp.is_valid()); 1408 __ movq(kScratchRegister,
1409 __ movq(temp.reg(), GlobalObject()); 1409 FieldOperand(kScratchRegister, GlobalObject::kBuiltinsOffset));
1410 __ movq(temp.reg(), 1410 frame_->Push(kScratchRegister);
William Hesse 2009/06/24 11:39:35 This must be reversed again - we cannot push kScra
1411 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
1412 frame_->Push(&temp);
1413 } 1411 }
1414 1412
1415 // Push the arguments ("left-to-right"). 1413 // Push the arguments ("left-to-right").
1416 int arg_count = args->length(); 1414 int arg_count = args->length();
1417 for (int i = 0; i < arg_count; i++) { 1415 for (int i = 0; i < arg_count; i++) {
1418 Load(args->at(i)); 1416 Load(args->at(i));
1419 } 1417 }
1420 1418
1421 if (function == NULL) { 1419 if (function == NULL) {
1422 // Call the JS runtime function. 1420 // Call the JS runtime function.
(...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after
2290 int MinorKey() { 2288 int MinorKey() {
2291 // Encode the parameters in a unique 16 bit value. 2289 // Encode the parameters in a unique 16 bit value.
2292 return OpBits::encode(op_) 2290 return OpBits::encode(op_)
2293 | ModeBits::encode(mode_) 2291 | ModeBits::encode(mode_)
2294 | FlagBits::encode(flags_); 2292 | FlagBits::encode(flags_);
2295 } 2293 }
2296 void Generate(MacroAssembler* masm); 2294 void Generate(MacroAssembler* masm);
2297 }; 2295 };
2298 2296
2299 2297
2298 class DeferredInlineBinaryOperation: public DeferredCode {
2299 public:
2300 DeferredInlineBinaryOperation(Token::Value op,
2301 Register dst,
2302 Register left,
2303 Register right,
2304 OverwriteMode mode)
2305 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) {
2306 set_comment("[ DeferredInlineBinaryOperation");
2307 }
2308
2309 virtual void Generate();
2310
2311 private:
2312 Token::Value op_;
2313 Register dst_;
2314 Register left_;
2315 Register right_;
2316 OverwriteMode mode_;
2317 };
2318
2319
2320 void DeferredInlineBinaryOperation::Generate() {
2321 __ push(left_);
2322 __ push(right_);
2323 GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED);
2324 __ CallStub(&stub);
2325 if (!dst_.is(rax)) __ movq(dst_, rax);
2326 }
2327
2328
2300 void CodeGenerator::GenericBinaryOperation(Token::Value op, 2329 void CodeGenerator::GenericBinaryOperation(Token::Value op,
2301 SmiAnalysis* type, 2330 SmiAnalysis* type,
2302 OverwriteMode overwrite_mode) { 2331 OverwriteMode overwrite_mode) {
2303 Comment cmnt(masm_, "[ BinaryOperation"); 2332 Comment cmnt(masm_, "[ BinaryOperation");
2304 Comment cmnt_token(masm_, Token::String(op)); 2333 Comment cmnt_token(masm_, Token::String(op));
2305 2334
2306 if (op == Token::COMMA) { 2335 if (op == Token::COMMA) {
2307 // Simply discard left value. 2336 // Simply discard left value.
2308 frame_->Nip(1); 2337 frame_->Nip(1);
2309 return; 2338 return;
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after
2616 } else { 2645 } else {
2617 LikelySmiBinaryOperation(op, operand, &constant_operand, 2646 LikelySmiBinaryOperation(op, operand, &constant_operand,
2618 overwrite_mode); 2647 overwrite_mode);
2619 } 2648 }
2620 break; 2649 break;
2621 } 2650 }
2622 } 2651 }
2623 ASSERT(!operand->is_valid()); 2652 ASSERT(!operand->is_valid());
2624 } 2653 }
2625 2654
2655 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
2656 Result* left,
2657 Result* right,
2658 OverwriteMode overwrite_mode) {
2659 // Special handling of div and mod because they use fixed registers.
2660 if (op == Token::DIV || op == Token::MOD) {
2661 // We need rax as the quotient register, rdx as the remainder
2662 // register, neither left nor right in rax or rdx, and left copied
2663 // to rax.
2664 Result quotient;
2665 Result remainder;
2666 bool left_is_in_rax = false;
2667 // Step 1: get rax for quotient.
2668 if ((left->is_register() && left->reg().is(rax)) ||
2669 (right->is_register() && right->reg().is(rax))) {
2670 // One or both is in rax. Use a fresh non-rdx register for
2671 // them.
2672 Result fresh = allocator_->Allocate();
2673 ASSERT(fresh.is_valid());
2674 if (fresh.reg().is(rdx)) {
2675 remainder = fresh;
2676 fresh = allocator_->Allocate();
2677 ASSERT(fresh.is_valid());
2678 }
2679 if (left->is_register() && left->reg().is(rax)) {
2680 quotient = *left;
2681 *left = fresh;
2682 left_is_in_rax = true;
2683 }
2684 if (right->is_register() && right->reg().is(rax)) {
2685 quotient = *right;
2686 *right = fresh;
2687 }
2688 __ movq(fresh.reg(), rax);
2689 } else {
2690 // Neither left nor right is in rax.
2691 quotient = allocator_->Allocate(rax);
2692 }
2693 ASSERT(quotient.is_register() && quotient.reg().is(rax));
2694 ASSERT(!(left->is_register() && left->reg().is(rax)));
2695 ASSERT(!(right->is_register() && right->reg().is(rax)));
2696
2697 // Step 2: get rdx for remainder if necessary.
2698 if (!remainder.is_valid()) {
2699 if ((left->is_register() && left->reg().is(rdx)) ||
2700 (right->is_register() && right->reg().is(rdx))) {
2701 Result fresh = allocator_->Allocate();
2702 ASSERT(fresh.is_valid());
2703 if (left->is_register() && left->reg().is(rdx)) {
2704 remainder = *left;
2705 *left = fresh;
2706 }
2707 if (right->is_register() && right->reg().is(rdx)) {
2708 remainder = *right;
2709 *right = fresh;
2710 }
2711 __ movq(fresh.reg(), rdx);
2712 } else {
2713 // Neither left nor right is in rdx.
2714 remainder = allocator_->Allocate(rdx);
2715 }
2716 }
2717 ASSERT(remainder.is_register() && remainder.reg().is(rdx));
2718 ASSERT(!(left->is_register() && left->reg().is(rdx)));
2719 ASSERT(!(right->is_register() && right->reg().is(rdx)));
2720
2721 left->ToRegister();
2722 right->ToRegister();
2723 frame_->Spill(rax);
2724 frame_->Spill(rdx);
2725
2726 // Check that left and right are smi tagged.
2727 DeferredInlineBinaryOperation* deferred =
2728 new DeferredInlineBinaryOperation(op,
2729 (op == Token::DIV) ? rax : rdx,
2730 left->reg(),
2731 right->reg(),
2732 overwrite_mode);
2733 if (left->reg().is(right->reg())) {
2734 __ testl(left->reg(), Immediate(kSmiTagMask));
2735 } else {
2736 // Use the quotient register as a scratch for the tag check.
2737 if (!left_is_in_rax) __ movq(rax, left->reg());
2738 left_is_in_rax = false; // About to destroy the value in rax.
2739 __ or_(rax, right->reg());
2740 ASSERT(kSmiTag == 0); // Adjust test if not the case.
2741 __ testl(rax, Immediate(kSmiTagMask));
2742 }
2743 deferred->Branch(not_zero);
2744
2745 if (!left_is_in_rax) __ movq(rax, left->reg());
2746 // Sign extend rax into rdx:rax.
2747 __ cqo();
2748 // Check for 0 divisor.
2749 __ testq(right->reg(), right->reg());
2750 deferred->Branch(zero);
2751 // Divide rdx:rax by the right operand.
2752 __ idiv(right->reg());
2753
2754 // Complete the operation.
2755 if (op == Token::DIV) {
2756 // Check for negative zero result. If result is zero, and divisor
2757 // is negative, return a floating point negative zero. The
2758 // virtual frame is unchanged in this block, so local control flow
2759 // can use a Label rather than a JumpTarget.
2760 Label non_zero_result;
2761 __ testq(left->reg(), left->reg());
2762 __ j(not_zero, &non_zero_result);
2763 __ testq(right->reg(), right->reg());
2764 deferred->Branch(negative);
2765 __ bind(&non_zero_result);
2766 // Check for the corner case of dividing the most negative smi by
2767 // -1. We cannot use the overflow flag, since it is not set by
2768 // idiv instruction.
2769 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2770 __ cmpq(rax, Immediate(0x40000000));
2771 deferred->Branch(equal);
2772 // Check that the remainder is zero.
2773 __ testq(rdx, rdx);
2774 deferred->Branch(not_zero);
2775 // Tag the result and store it in the quotient register.
2776 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
2777 __ lea(rax, Operand(rax, rax, times_1, kSmiTag));
2778 deferred->BindExit();
2779 left->Unuse();
2780 right->Unuse();
2781 frame_->Push(&quotient);
2782 } else {
2783 ASSERT(op == Token::MOD);
2784 // Check for a negative zero result. If the result is zero, and
2785 // the dividend is negative, return a floating point negative
2786 // zero. The frame is unchanged in this block, so local control
2787 // flow can use a Label rather than a JumpTarget.
2788 Label non_zero_result;
2789 __ testq(rdx, rdx);
2790 __ j(not_zero, &non_zero_result);
2791 __ testq(left->reg(), left->reg());
2792 deferred->Branch(negative);
2793 __ bind(&non_zero_result);
2794 deferred->BindExit();
2795 left->Unuse();
2796 right->Unuse();
2797 frame_->Push(&remainder);
2798 }
2799 return;
2800 }
2801
2802 // Special handling of shift operations because they use fixed
2803 // registers.
2804 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) {
2805 // Move left out of rcx if necessary.
2806 if (left->is_register() && left->reg().is(rcx)) {
2807 *left = allocator_->Allocate();
2808 ASSERT(left->is_valid());
2809 __ movq(left->reg(), rcx);
2810 }
2811 right->ToRegister(rcx);
2812 left->ToRegister();
2813 ASSERT(left->is_register() && !left->reg().is(rcx));
2814 ASSERT(right->is_register() && right->reg().is(rcx));
2815
2816 // We will modify right, it must be spilled.
2817 frame_->Spill(rcx);
2818
2819 // Use a fresh answer register to avoid spilling the left operand.
2820 Result answer = allocator_->Allocate();
2821 ASSERT(answer.is_valid());
2822 // Check that both operands are smis using the answer register as a
2823 // temporary.
2824 DeferredInlineBinaryOperation* deferred =
2825 new DeferredInlineBinaryOperation(op,
2826 answer.reg(),
2827 left->reg(),
2828 rcx,
2829 overwrite_mode);
2830 __ movq(answer.reg(), left->reg());
2831 __ or_(answer.reg(), rcx);
2832 __ testl(answer.reg(), Immediate(kSmiTagMask));
2833 deferred->Branch(not_zero);
2834
2835 // Untag both operands.
2836 __ movq(answer.reg(), left->reg());
2837 __ sar(answer.reg(), Immediate(kSmiTagSize));
2838 __ sar(rcx, Immediate(kSmiTagSize));
2839 // Perform the operation.
2840 switch (op) {
2841 case Token::SAR:
2842 __ sar(answer.reg());
2843 // No checks of result necessary
2844 break;
2845 case Token::SHR: {
2846 Label result_ok;
2847 __ shr(answer.reg());
2848 // Check that the *unsigned* result fits in a smi. Neither of
2849 // the two high-order bits can be set:
2850 // * 0x80000000: high bit would be lost when smi tagging.
2851 // * 0x40000000: this number would convert to negative when smi
2852 // tagging.
2853 // These two cases can only happen with shifts by 0 or 1 when
2854 // handed a valid smi. If the answer cannot be represented by a
2855 // smi, restore the left and right arguments, and jump to slow
2856 // case. The low bit of the left argument may be lost, but only
2857 // in a case where it is dropped anyway.
2858 __ testl(answer.reg(), Immediate(0xc0000000));
2859 __ j(zero, &result_ok);
2860 ASSERT(kSmiTag == 0);
2861 __ shl(rcx, Immediate(kSmiTagSize));
2862 deferred->Jump();
2863 __ bind(&result_ok);
2864 break;
2865 }
2866 case Token::SHL: {
2867 Label result_ok;
2868 __ shl(answer.reg());
2869 // Check that the *signed* result fits in a smi.
2870 __ cmpq(answer.reg(), Immediate(0xc0000000));
2871 __ j(positive, &result_ok);
2872 ASSERT(kSmiTag == 0);
2873 __ shl(rcx, Immediate(kSmiTagSize));
2874 deferred->Jump();
2875 __ bind(&result_ok);
2876 break;
2877 }
2878 default:
2879 UNREACHABLE();
2880 }
2881 // Smi-tag the result in answer.
2882 ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
2883 __ lea(answer.reg(),
2884 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
2885 deferred->BindExit();
2886 left->Unuse();
2887 right->Unuse();
2888 frame_->Push(&answer);
2889 return;
2890 }
2891
2892 // Handle the other binary operations.
2893 left->ToRegister();
2894 right->ToRegister();
2895 // A newly allocated register answer is used to hold the answer. The
2896 // registers containing left and right are not modified so they don't
2897 // need to be spilled in the fast case.
2898 Result answer = allocator_->Allocate();
2899 ASSERT(answer.is_valid());
2900
2901 // Perform the smi tag check.
2902 DeferredInlineBinaryOperation* deferred =
2903 new DeferredInlineBinaryOperation(op,
2904 answer.reg(),
2905 left->reg(),
2906 right->reg(),
2907 overwrite_mode);
2908 if (left->reg().is(right->reg())) {
2909 __ testl(left->reg(), Immediate(kSmiTagMask));
2910 } else {
2911 __ movq(answer.reg(), left->reg());
2912 __ or_(answer.reg(), right->reg());
2913 ASSERT(kSmiTag == 0); // Adjust test if not the case.
2914 __ testl(answer.reg(), Immediate(kSmiTagMask));
2915 }
2916 deferred->Branch(not_zero);
2917 __ movq(answer.reg(), left->reg());
2918 switch (op) {
2919 case Token::ADD:
2920 __ addq(answer.reg(), right->reg()); // Add optimistically.
William Hesse 2009/06/24 11:39:35 I think we want addl here.
2921 deferred->Branch(overflow);
2922 break;
2923
2924 case Token::SUB:
2925 __ subq(answer.reg(), right->reg()); // Subtract optimistically.
William Hesse 2009/06/24 11:39:35 subl
2926 deferred->Branch(overflow);
2927 break;
2928
2929 case Token::MUL: {
2930 // If the smi tag is 0 we can just leave the tag on one operand.
2931 ASSERT(kSmiTag == 0); // Adjust code below if not the case.
2932 // Remove smi tag from the left operand (but keep sign).
2933 // Left-hand operand has been copied into answer.
2934 __ sar(answer.reg(), Immediate(kSmiTagSize));
2935 // Do multiplication of smis, leaving result in answer.
2936 __ imull(answer.reg(), right->reg());
2937 // Go slow on overflows.
2938 deferred->Branch(overflow);
2939 // Check for negative zero result. If product is zero, and one
2940 // argument is negative, go to slow case. The frame is unchanged
2941 // in this block, so local control flow can use a Label rather
2942 // than a JumpTarget.
2943 Label non_zero_result;
2944 __ testq(answer.reg(), answer.reg());
2945 __ j(not_zero, &non_zero_result);
2946 __ movq(answer.reg(), left->reg());
2947 __ or_(answer.reg(), right->reg());
2948 deferred->Branch(negative);
2949 __ xor_(answer.reg(), answer.reg()); // Positive 0 is correct.
2950 __ bind(&non_zero_result);
2951 break;
2952 }
2953
2954 case Token::BIT_OR:
2955 __ or_(answer.reg(), right->reg());
2956 break;
2957
2958 case Token::BIT_AND:
2959 __ and_(answer.reg(), right->reg());
2960 break;
2961
2962 case Token::BIT_XOR:
2963 __ xor_(answer.reg(), right->reg());
2964 break;
2965
2966 default:
2967 UNREACHABLE();
2968 break;
2969 }
2970 deferred->BindExit();
2971 left->Unuse();
2972 right->Unuse();
2973 frame_->Push(&answer);
2974 }
2975
2976
2626 #undef __ 2977 #undef __
2627 #define __ ACCESS_MASM(masm) 2978 #define __ ACCESS_MASM(masm)
2628 2979
2629 2980
2630 Handle<String> Reference::GetName() { 2981 Handle<String> Reference::GetName() {
2631 ASSERT(type_ == NAMED); 2982 ASSERT(type_ == NAMED);
2632 Property* property = expression_->AsProperty(); 2983 Property* property = expression_->AsProperty();
2633 if (property == NULL) { 2984 if (property == NULL) {
2634 // Global variable reference treated as a named property reference. 2985 // Global variable reference treated as a named property reference.
2635 VariableProxy* proxy = expression_->AsVariableProxy(); 2986 VariableProxy* proxy = expression_->AsVariableProxy();
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2676 if (is_global || 3027 if (is_global ||
2677 cgen_->scope()->is_global_scope() || 3028 cgen_->scope()->is_global_scope() ||
2678 cgen_->loop_nesting() == 0) { 3029 cgen_->loop_nesting() == 0) {
2679 Comment cmnt(masm, "[ Load from named Property"); 3030 Comment cmnt(masm, "[ Load from named Property");
2680 cgen_->frame()->Push(GetName()); 3031 cgen_->frame()->Push(GetName());
2681 3032
2682 RelocInfo::Mode mode = is_global 3033 RelocInfo::Mode mode = is_global
2683 ? RelocInfo::CODE_TARGET_CONTEXT 3034 ? RelocInfo::CODE_TARGET_CONTEXT
2684 : RelocInfo::CODE_TARGET; 3035 : RelocInfo::CODE_TARGET;
2685 Result answer = cgen_->frame()->CallLoadIC(mode); 3036 Result answer = cgen_->frame()->CallLoadIC(mode);
2686 // A test eax instruction following the call signals that the 3037 // A test rax instruction following the call signals that the
2687 // inobject property case was inlined. Ensure that there is not 3038 // inobject property case was inlined. Ensure that there is not
2688 // a test eax instruction here. 3039 // a test rax instruction here.
2689 __ nop(); 3040 __ nop();
2690 cgen_->frame()->Push(&answer); 3041 cgen_->frame()->Push(&answer);
2691 } else { 3042 } else {
2692 // Inline the inobject property case. 3043 // Inline the inobject property case.
2693 Comment cmnt(masm, "[ Inlined named property load"); 3044 Comment cmnt(masm, "[ Inlined named property load");
2694 Result receiver = cgen_->frame()->Pop(); 3045 Result receiver = cgen_->frame()->Pop();
2695 receiver.ToRegister(); 3046 receiver.ToRegister();
2696 3047
2697 Result value = cgen_->allocator()->Allocate(); 3048 Result value = cgen_->allocator()->Allocate();
2698 ASSERT(value.is_valid()); 3049 ASSERT(value.is_valid());
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
2863 __ bind(&true_result); 3214 __ bind(&true_result);
2864 __ movq(rax, Immediate(1)); 3215 __ movq(rax, Immediate(1));
2865 __ ret(1 * kPointerSize); 3216 __ ret(1 * kPointerSize);
2866 __ bind(&false_result); 3217 __ bind(&false_result);
2867 __ xor_(rax, rax); 3218 __ xor_(rax, rax);
2868 __ ret(1 * kPointerSize); 3219 __ ret(1 * kPointerSize);
2869 } 3220 }
2870 3221
2871 3222
2872 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { 3223 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
2873 return false; // UNIMPLEMENTED. 3224 // TODO(X64): This method is identical to the ia32 version.
3225 // Either find a reason to change it, or move it somewhere where it can be
3226 // shared. (Notice: It assumes that a Smi can fit in an int).
3227
3228 Object* answer_object = Heap::undefined_value();
3229 switch (op) {
3230 case Token::ADD:
3231 if (Smi::IsValid(left + right)) {
3232 answer_object = Smi::FromInt(left + right);
3233 }
3234 break;
3235 case Token::SUB:
3236 if (Smi::IsValid(left - right)) {
3237 answer_object = Smi::FromInt(left - right);
3238 }
3239 break;
3240 case Token::MUL: {
3241 double answer = static_cast<double>(left) * right;
3242 if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) {
3243 // If the product is zero and the non-zero factor is negative,
3244 // the spec requires us to return floating point negative zero.
3245 if (answer != 0 || (left >= 0 && right >= 0)) {
3246 answer_object = Smi::FromInt(static_cast<int>(answer));
3247 }
3248 }
3249 }
3250 break;
3251 case Token::DIV:
3252 case Token::MOD:
3253 break;
3254 case Token::BIT_OR:
3255 answer_object = Smi::FromInt(left | right);
3256 break;
3257 case Token::BIT_AND:
3258 answer_object = Smi::FromInt(left & right);
3259 break;
3260 case Token::BIT_XOR:
3261 answer_object = Smi::FromInt(left ^ right);
3262 break;
3263
3264 case Token::SHL: {
3265 int shift_amount = right & 0x1F;
3266 if (Smi::IsValid(left << shift_amount)) {
3267 answer_object = Smi::FromInt(left << shift_amount);
3268 }
3269 break;
3270 }
3271 case Token::SHR: {
3272 int shift_amount = right & 0x1F;
3273 unsigned int unsigned_left = left;
3274 unsigned_left >>= shift_amount;
3275 if (unsigned_left <= static_cast<unsigned int>(Smi::kMaxValue)) {
3276 answer_object = Smi::FromInt(unsigned_left);
3277 }
3278 break;
3279 }
3280 case Token::SAR: {
3281 int shift_amount = right & 0x1F;
3282 unsigned int unsigned_left = left;
3283 if (left < 0) {
3284 // Perform arithmetic shift of a negative number by
3285 // complementing number, logical shifting, complementing again.
3286 unsigned_left = ~unsigned_left;
3287 unsigned_left >>= shift_amount;
3288 unsigned_left = ~unsigned_left;
3289 } else {
3290 unsigned_left >>= shift_amount;
3291 }
3292 ASSERT(Smi::IsValid(unsigned_left)); // Converted to signed.
3293 answer_object = Smi::FromInt(unsigned_left); // Converted to signed.
3294 break;
3295 }
3296 default:
3297 UNREACHABLE();
3298 break;
3299 }
3300 if (answer_object == Heap::undefined_value()) {
3301 return false;
3302 }
3303 frame_->Push(Handle<Object>(answer_object));
3304 return true;
2874 } 3305 }
2875 3306
2876 3307
2877 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
2878 Result* left,
2879 Result* right,
2880 OverwriteMode overwrite_mode) {
2881 UNIMPLEMENTED();
2882 }
2883 3308
2884 3309
2885 // End of CodeGenerator implementation. 3310 // End of CodeGenerator implementation.
2886 3311
2887 void UnarySubStub::Generate(MacroAssembler* masm) { 3312 void UnarySubStub::Generate(MacroAssembler* masm) {
2888 UNIMPLEMENTED(); 3313 UNIMPLEMENTED();
2889 } 3314 }
2890 3315
2891 class CompareStub: public CodeStub { 3316 class CompareStub: public CodeStub {
2892 public: 3317 public:
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after
3562 __ testl(rdx, Immediate(kSmiTagMask)); 3987 __ testl(rdx, Immediate(kSmiTagMask));
3563 __ j(zero, &test_other); // argument in rdx is OK 3988 __ j(zero, &test_other); // argument in rdx is OK
3564 __ movq(kScratchRegister, 3989 __ movq(kScratchRegister,
3565 Factory::heap_number_map(), 3990 Factory::heap_number_map(),
3566 RelocInfo::EMBEDDED_OBJECT); 3991 RelocInfo::EMBEDDED_OBJECT);
3567 __ cmpq(kScratchRegister, FieldOperand(rdx, HeapObject::kMapOffset)); 3992 __ cmpq(kScratchRegister, FieldOperand(rdx, HeapObject::kMapOffset));
3568 __ j(not_equal, non_float); // argument in rdx is not a number -> NaN 3993 __ j(not_equal, non_float); // argument in rdx is not a number -> NaN
3569 3994
3570 __ bind(&test_other); 3995 __ bind(&test_other);
3571 __ testl(rax, Immediate(kSmiTagMask)); 3996 __ testl(rax, Immediate(kSmiTagMask));
3572 __ j(zero, &done); // argument in eax is OK 3997 __ j(zero, &done); // argument in rax is OK
3573 __ movq(kScratchRegister, 3998 __ movq(kScratchRegister,
3574 Factory::heap_number_map(), 3999 Factory::heap_number_map(),
3575 RelocInfo::EMBEDDED_OBJECT); 4000 RelocInfo::EMBEDDED_OBJECT);
3576 __ cmpq(kScratchRegister, FieldOperand(rax, HeapObject::kMapOffset)); 4001 __ cmpq(kScratchRegister, FieldOperand(rax, HeapObject::kMapOffset));
3577 __ j(not_equal, non_float); // argument in rax is not a number -> NaN 4002 __ j(not_equal, non_float); // argument in rax is not a number -> NaN
3578 4003
3579 // Fall-through: Both operands are numbers. 4004 // Fall-through: Both operands are numbers.
3580 __ bind(&done); 4005 __ bind(&done);
3581 } 4006 }
3582 4007
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
3990 break; 4415 break;
3991 default: 4416 default:
3992 UNREACHABLE(); 4417 UNREACHABLE();
3993 } 4418 }
3994 } 4419 }
3995 4420
3996 4421
3997 #undef __ 4422 #undef __
3998 4423
3999 } } // namespace v8::internal 4424 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698