| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 __ movl(Address(EBP, exception_var().index() * kWordSize), | 747 __ movl(Address(EBP, exception_var().index() * kWordSize), |
| 748 kExceptionObjectReg); | 748 kExceptionObjectReg); |
| 749 __ movl(Address(EBP, stacktrace_var().index() * kWordSize), | 749 __ movl(Address(EBP, stacktrace_var().index() * kWordSize), |
| 750 kStackTraceObjectReg); | 750 kStackTraceObjectReg); |
| 751 } | 751 } |
| 752 | 752 |
| 753 | 753 |
| 754 LocationSummary* BinaryOpComp::MakeLocationSummary() const { | 754 LocationSummary* BinaryOpComp::MakeLocationSummary() const { |
| 755 const intptr_t kNumInputs = 2; | 755 const intptr_t kNumInputs = 2; |
| 756 const intptr_t kNumTemps = 0; | 756 const intptr_t kNumTemps = 0; |
| 757 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 757 if (operands_type() == kDoubleOperands) { |
| 758 summary->set_in(0, Location::RequiresRegister()); | 758 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 759 summary->set_in(1, Location::RequiresRegister()); | 759 summary->set_in(0, Location::RequiresRegister()); |
| 760 summary->set_out(Location::SameAsFirstInput()); | 760 summary->set_in(1, Location::RequiresRegister()); |
| 761 return summary; | 761 summary->set_out(Location::SameAsFirstInput()); |
| 762 } | 762 return summary; |
| 763 | 763 } |
| 764 | 764 ASSERT(operands_type() == kSmiOperands); |
| 765 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 765 if (op_kind() == Token::kTRUNCDIV) { |
| 766 const intptr_t kNumTemps = 3; |
| 767 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 768 summary->set_in(0, Location::RegisterLocation(EAX)); |
| 769 summary->set_in(1, Location::RegisterLocation(ECX)); |
| 770 summary->set_out(Location::SameAsFirstInput()); |
| 771 summary->set_temp(0, Location::RegisterLocation(EBX)); |
| 772 // Will be used for for sign extension. |
| 773 summary->set_temp(1, Location::RegisterLocation(EDX)); |
| 774 summary->set_temp(2, Location::RequiresRegister()); |
| 775 return summary; |
| 776 } else if (op_kind() == Token::kSHR) { |
| 777 const intptr_t kNumTemps = 1; |
| 778 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 779 summary->set_in(0, Location::RequiresRegister()); |
| 780 summary->set_in(1, Location::RegisterLocation(ECX)); |
| 781 summary->set_out(Location::SameAsFirstInput()); |
| 782 summary->set_temp(0, Location::RequiresRegister()); |
| 783 return summary; |
| 784 } else if (op_kind() == Token::kSHL) { |
| 785 const intptr_t kNumTemps = 2; |
| 786 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 787 summary->set_in(0, Location::RequiresRegister()); |
| 788 summary->set_in(1, Location::RequiresRegister()); |
| 789 summary->set_out(Location::SameAsFirstInput()); |
| 790 summary->set_temp(0, Location::RequiresRegister()); |
| 791 summary->set_temp(1, Location::RegisterLocation(ECX)); |
| 792 return summary; |
| 793 } else { |
| 794 const intptr_t kNumTemps = 1; |
| 795 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 796 summary->set_in(0, Location::RequiresRegister()); |
| 797 summary->set_in(1, Location::RequiresRegister()); |
| 798 summary->set_out(Location::SameAsFirstInput()); |
| 799 summary->set_temp(0, Location::RequiresRegister()); |
| 800 return summary; |
| 801 } |
| 802 } |
| 803 |
| 804 |
| 805 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { |
| 806 Register left = comp->locs()->in(0).reg(); |
| 807 Register right = comp->locs()->in(1).reg(); |
| 808 Register result = comp->locs()->out().reg(); |
| 809 Register temp = comp->locs()->temp(0).reg(); |
| 810 ASSERT(left == result); |
| 811 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), |
| 812 comp->instance_call()->token_index(), |
| 813 comp->instance_call()->try_index(), |
| 814 kDeoptSmiBinaryOp, |
| 815 temp, |
| 816 right); |
| 817 __ movl(temp, left); |
| 818 __ orl(left, right); |
| 819 __ testl(left, Immediate(kSmiTagMask)); |
| 820 __ j(NOT_ZERO, deopt); |
| 821 __ movl(left, temp); |
| 822 switch (comp->op_kind()) { |
| 823 case Token::kADD: { |
| 824 __ addl(left, right); |
| 825 __ j(OVERFLOW, deopt); |
| 826 break; |
| 827 } |
| 828 case Token::kSUB: { |
| 829 __ subl(left, right); |
| 830 __ j(OVERFLOW, deopt); |
| 831 break; |
| 832 } |
| 833 case Token::kMUL: { |
| 834 __ SmiUntag(left); |
| 835 __ imull(left, right); |
| 836 __ j(OVERFLOW, deopt); |
| 837 break; |
| 838 } |
| 839 case Token::kBIT_AND: { |
| 840 // No overflow check. |
| 841 __ andl(left, right); |
| 842 break; |
| 843 } |
| 844 case Token::kBIT_OR: { |
| 845 // No overflow check. |
| 846 __ orl(left, right); |
| 847 break; |
| 848 } |
| 849 case Token::kBIT_XOR: { |
| 850 // No overflow check. |
| 851 __ xorl(left, right); |
| 852 break; |
| 853 } |
| 854 case Token::kTRUNCDIV: { |
| 855 // Handle divide by zero in runtime. |
| 856 // Deoptimization requires that temp and right are preserved. |
| 857 __ testl(right, right); |
| 858 __ j(ZERO, deopt); |
| 859 ASSERT(left == EAX); |
| 860 ASSERT((right != EDX) && (right != EAX)); |
| 861 ASSERT((temp != EDX) && (temp != EAX)); |
| 862 ASSERT(comp->locs()->temp(1).reg() == EDX); |
| 863 ASSERT(result == EAX); |
| 864 Register right_temp = comp->locs()->temp(2).reg(); |
| 865 __ movl(right_temp, right); |
| 866 __ SmiUntag(left); |
| 867 __ SmiUntag(right_temp); |
| 868 __ cdq(); // Sign extend EAX -> EDX:EAX. |
| 869 __ idivl(right_temp); // EAX: quotient, EDX: remainder. |
| 870 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 871 // case we cannot tag the result. |
| 872 __ cmpl(result, Immediate(0x40000000)); |
| 873 __ j(EQUAL, deopt); |
| 874 __ SmiTag(result); |
| 875 break; |
| 876 } |
| 877 case Token::kSHR: { |
| 878 // The count is masked to 5 bits on ia32. |
| 879 const Immediate kCountLimit = Immediate(0x1F); |
| 880 __ cmpl(right, Immediate(0)); |
| 881 __ j(LESS, deopt); |
| 882 __ SmiUntag(right); |
| 883 __ cmpl(right, kCountLimit); |
| 884 Label count_ok; |
| 885 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 886 __ movl(right, kCountLimit); |
| 887 __ Bind(&count_ok); |
| 888 ASSERT(right == ECX); // Count must be in ECX |
| 889 __ SmiUntag(left); |
| 890 __ sarl(left, right); |
| 891 __ SmiTag(left); |
| 892 break; |
| 893 } |
| 894 case Token::kSHL: { |
| 895 // Check if count too large for handling it inlined. |
| 896 __ cmpl(right, |
| 897 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); |
| 898 __ j(ABOVE_EQUAL, deopt); |
| 899 Register right_temp = comp->locs()->temp(1).reg(); |
| 900 ASSERT(right_temp == ECX); // Count must be in ECX |
| 901 __ movl(right_temp, right); |
| 902 __ SmiUntag(right_temp); |
| 903 // Overflow test (preserve temp and right); |
| 904 __ shll(left, right_temp); |
| 905 __ sarl(left, right_temp); |
| 906 __ cmpl(left, temp); |
| 907 __ j(NOT_EQUAL, deopt); // Overflow. |
| 908 // Shift for result now we know there is no overflow. |
| 909 __ shll(left, right_temp); |
| 910 break; |
| 911 } |
| 912 case Token::kDIV: { |
| 913 // Dispatches to 'Double./'. |
| 914 // TODO(srdjan): Implement as conversion to double and double division. |
| 915 UNREACHABLE(); |
| 916 break; |
| 917 } |
| 918 case Token::kMOD: { |
| 919 // TODO(srdjan): Implement. |
| 920 UNREACHABLE(); |
| 921 break; |
| 922 } |
| 923 case Token::kOR: |
| 924 case Token::kAND: { |
| 925 // Flow graph builder has dissected this operation to guarantee correct |
| 926 // behavior (short-circuit evaluation). |
| 927 UNREACHABLE(); |
| 928 break; |
| 929 } |
| 930 default: |
| 931 UNREACHABLE(); |
| 932 break; |
| 933 } |
| 934 } |
| 935 |
| 936 |
| 937 static void EmitDoubleBinaryOp(FlowGraphCompiler* compiler, |
| 938 BinaryOpComp* comp) { |
| 766 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted | 939 // TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted |
| 767 // for all intended operations. | 940 // for all intended operations. |
| 768 Register left = locs()->in(0).reg(); | 941 Register left = comp->locs()->in(0).reg(); |
| 769 Register right = locs()->in(1).reg(); | 942 Register right = comp->locs()->in(1).reg(); |
| 770 __ pushl(left); | 943 __ pushl(left); |
| 771 __ pushl(right); | 944 __ pushl(right); |
| 772 InstanceCallComp* instance_call_comp = instance_call(); | 945 InstanceCallComp* instance_call_comp = comp->instance_call(); |
| 773 instance_call_comp->EmitNativeCode(compiler); | 946 instance_call_comp->EmitNativeCode(compiler); |
| 774 if (locs()->out().reg() != EAX) { | 947 __ MoveRegister(comp->locs()->out().reg(), EAX); |
| 775 __ movl(locs()->out().reg(), EAX); | 948 } |
| 776 } | 949 |
| 777 } | 950 |
| 778 | 951 void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 952 switch (operands_type()) { |
| 953 case kSmiOperands: |
| 954 EmitSmiBinaryOp(compiler, this); |
| 955 break; |
| 956 |
| 957 case kDoubleOperands: |
| 958 EmitDoubleBinaryOp(compiler, this); |
| 959 break; |
| 960 |
| 961 default: |
| 962 UNREACHABLE(); |
| 963 } |
| 964 } |
| 965 |
| 779 | 966 |
| 780 LocationSummary* UnarySmiOpComp::MakeLocationSummary() const { | 967 LocationSummary* UnarySmiOpComp::MakeLocationSummary() const { |
| 781 const intptr_t kNumInputs = 1; | 968 const intptr_t kNumInputs = 1; |
| 782 const intptr_t kNumTemps = 0; | 969 const intptr_t kNumTemps = 0; |
| 783 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 970 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 784 summary->set_in(0, Location::RequiresRegister()); | 971 summary->set_in(0, Location::RequiresRegister()); |
| 785 summary->set_out(Location::SameAsFirstInput()); | 972 summary->set_out(Location::SameAsFirstInput()); |
| 786 return summary; | 973 return summary; |
| 787 } | 974 } |
| 788 | 975 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 UNREACHABLE(); | 1073 UNREACHABLE(); |
| 887 } | 1074 } |
| 888 } | 1075 } |
| 889 | 1076 |
| 890 | 1077 |
| 891 } // namespace dart | 1078 } // namespace dart |
| 892 | 1079 |
| 893 #undef __ | 1080 #undef __ |
| 894 | 1081 |
| 895 #endif // defined TARGET_ARCH_X64 | 1082 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |