| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 4882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4893 // Temp index 1. | 4893 // Temp index 1. |
| 4894 result->AddTemp(Location::RegisterLocation(EAX)); | 4894 result->AddTemp(Location::RegisterLocation(EAX)); |
| 4895 // Temp index 2. | 4895 // Temp index 2. |
| 4896 result->AddTemp(Location::FpuRegisterLocation(XMM4)); | 4896 result->AddTemp(Location::FpuRegisterLocation(XMM4)); |
| 4897 } | 4897 } |
| 4898 result->set_out(0, Location::FpuRegisterLocation(XMM3)); | 4898 result->set_out(0, Location::FpuRegisterLocation(XMM3)); |
| 4899 return result; | 4899 return result; |
| 4900 } | 4900 } |
| 4901 | 4901 |
| 4902 | 4902 |
| 4903 // Pseudo code: |
| 4904 // if (exponent == 0.0) return 1.0; |
| 4905 // // Speed up simple cases. |
| 4906 // if (exponent == 1.0) return base; |
| 4907 // if (exponent == 2.0) return base * base; |
| 4908 // if (exponent == 3.0) return base * base * base; |
| 4909 // if (base == 1.0) return 1.0; |
| 4910 // if (base.isNaN || exponent.isNaN) { |
| 4911 // return double.NAN; |
| 4912 // } |
| 4913 // if (base != -Infinity && exponent == 0.5) { |
| 4914 // if (base == 0.0) return 0.0; |
| 4915 // return sqrt(value); |
| 4916 // } |
| 4917 // TODO(srdjan): Move into a stub? |
| 4918 static void InvokeDoublePow(FlowGraphCompiler* compiler, |
| 4919 InvokeMathCFunctionInstr* instr) { |
| 4920 ASSERT(instr->recognized_kind() == MethodRecognizer::kMathDoublePow); |
| 4921 const intptr_t kInputCount = 2; |
| 4922 ASSERT(instr->InputCount() == kInputCount); |
| 4923 LocationSummary* locs = instr->locs(); |
| 4924 |
| 4925 XmmRegister base = locs->in(0).fpu_reg(); |
| 4926 XmmRegister exp = locs->in(1).fpu_reg(); |
| 4927 XmmRegister result = locs->out(0).fpu_reg(); |
| 4928 Register temp = locs->temp(InvokeMathCFunctionInstr::kObjectTempIndex).reg(); |
| 4929 XmmRegister zero_temp = |
| 4930 locs->temp(InvokeMathCFunctionInstr::kDoubleTempIndex).fpu_reg(); |
| 4931 |
| 4932 __ xorps(zero_temp, zero_temp); // 0.0. |
| 4933 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1.0))); |
| 4934 __ movsd(result, FieldAddress(temp, Double::value_offset())); |
| 4935 |
| 4936 Label check_base, skip_call; |
| 4937 // exponent == 0.0 -> return 1.0; |
| 4938 __ comisd(exp, zero_temp); |
| 4939 __ j(PARITY_EVEN, &check_base); |
| 4940 __ j(EQUAL, &skip_call); // 'result' is 1.0. |
| 4941 |
| 4942 // exponent == 1.0 ? |
| 4943 __ comisd(exp, result); |
| 4944 Label return_base; |
| 4945 __ j(EQUAL, &return_base, Assembler::kNearJump); |
| 4946 |
| 4947 // exponent == 2.0 ? |
| 4948 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(2.0))); |
| 4949 __ movsd(XMM0, FieldAddress(temp, Double::value_offset())); |
| 4950 __ comisd(exp, XMM0); |
| 4951 Label return_base_times_2; |
| 4952 __ j(EQUAL, &return_base_times_2, Assembler::kNearJump); |
| 4953 |
| 4954 // exponent == 3.0 ? |
| 4955 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(3.0))); |
| 4956 __ movsd(XMM0, FieldAddress(temp, Double::value_offset())); |
| 4957 __ comisd(exp, XMM0); |
| 4958 __ j(NOT_EQUAL, &check_base); |
| 4959 |
| 4960 // Base times 3. |
| 4961 __ movsd(result, base); |
| 4962 __ mulsd(result, base); |
| 4963 __ mulsd(result, base); |
| 4964 __ jmp(&skip_call); |
| 4965 |
| 4966 __ Bind(&return_base); |
| 4967 __ movsd(result, base); |
| 4968 __ jmp(&skip_call); |
| 4969 |
| 4970 __ Bind(&return_base_times_2); |
| 4971 __ movsd(result, base); |
| 4972 __ mulsd(result, base); |
| 4973 __ jmp(&skip_call); |
| 4974 |
| 4975 __ Bind(&check_base); |
| 4976 // Note: 'exp' could be NaN. |
| 4977 |
| 4978 // base == 1.0 -> return 1.0; |
| 4979 __ comisd(base, result); |
| 4980 Label return_nan; |
| 4981 __ j(PARITY_EVEN, &return_nan, Assembler::kNearJump); |
| 4982 __ j(EQUAL, &skip_call, Assembler::kNearJump); |
| 4983 // Note: 'base' could be NaN. |
| 4984 __ comisd(exp, base); |
| 4985 // Neither 'exp' nor 'base' is NaN. |
| 4986 Label try_sqrt; |
| 4987 __ j(PARITY_ODD, &try_sqrt, Assembler::kNearJump); |
| 4988 // Return NaN. |
| 4989 __ Bind(&return_nan); |
| 4990 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(NAN))); |
| 4991 __ movsd(result, FieldAddress(temp, Double::value_offset())); |
| 4992 __ jmp(&skip_call); |
| 4993 |
| 4994 Label do_pow, return_zero; |
| 4995 __ Bind(&try_sqrt); |
| 4996 // Before calling pow, check if we could use sqrt instead of pow. |
| 4997 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(-INFINITY))); |
| 4998 __ movsd(result, FieldAddress(temp, Double::value_offset())); |
| 4999 // base == -Infinity -> call pow; |
| 5000 __ comisd(base, result); |
| 5001 __ j(EQUAL, &do_pow, Assembler::kNearJump); |
| 5002 |
| 5003 // exponent == 0.5 ? |
| 5004 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0.5))); |
| 5005 __ movsd(result, FieldAddress(temp, Double::value_offset())); |
| 5006 __ comisd(exp, result); |
| 5007 __ j(NOT_EQUAL, &do_pow, Assembler::kNearJump); |
| 5008 |
| 5009 // base == 0 -> return 0; |
| 5010 __ comisd(base, zero_temp); |
| 5011 __ j(EQUAL, &return_zero, Assembler::kNearJump); |
| 5012 |
| 5013 __ sqrtsd(result, base); |
| 5014 __ jmp(&skip_call, Assembler::kNearJump); |
| 5015 |
| 5016 __ Bind(&return_zero); |
| 5017 __ movsd(result, zero_temp); |
| 5018 __ jmp(&skip_call); |
| 5019 |
| 5020 __ Bind(&do_pow); |
| 5021 // Save ESP. |
| 5022 __ movl(locs->temp(InvokeMathCFunctionInstr::kSavedSpTempIndex).reg(), ESP); |
| 5023 __ ReserveAlignedFrameSpace(kDoubleSize * kInputCount); |
| 5024 for (intptr_t i = 0; i < kInputCount; i++) { |
| 5025 __ movsd(Address(ESP, kDoubleSize * i), locs->in(i).fpu_reg()); |
| 5026 } |
| 5027 __ CallRuntime(instr->TargetFunction(), kInputCount); |
| 5028 __ fstpl(Address(ESP, 0)); |
| 5029 __ movsd(locs->out(0).fpu_reg(), Address(ESP, 0)); |
| 5030 // Restore ESP. |
| 5031 __ movl(ESP, locs->temp(InvokeMathCFunctionInstr::kSavedSpTempIndex).reg()); |
| 5032 __ Bind(&skip_call); |
| 5033 } |
| 5034 |
| 5035 |
| 4903 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5036 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5037 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { |
| 5038 InvokeDoublePow(compiler, this); |
| 5039 return; |
| 5040 } |
| 4904 // Save ESP. | 5041 // Save ESP. |
| 4905 __ movl(locs()->temp(kSavedSpTempIndex).reg(), ESP); | 5042 __ movl(locs()->temp(kSavedSpTempIndex).reg(), ESP); |
| 4906 __ ReserveAlignedFrameSpace(kDoubleSize * InputCount()); | 5043 __ ReserveAlignedFrameSpace(kDoubleSize * InputCount()); |
| 4907 for (intptr_t i = 0; i < InputCount(); i++) { | 5044 for (intptr_t i = 0; i < InputCount(); i++) { |
| 4908 __ movsd(Address(ESP, kDoubleSize * i), locs()->in(i).fpu_reg()); | 5045 __ movsd(Address(ESP, kDoubleSize * i), locs()->in(i).fpu_reg()); |
| 4909 } | 5046 } |
| 4910 Label skip_call; | |
| 4911 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { | |
| 4912 // Pseudo code: | |
| 4913 // if (exponent == 0.0) return 1.0; | |
| 4914 // if (base == 1.0) return 1.0; | |
| 4915 // if (base.isNaN || exponent.isNaN) { | |
| 4916 // return double.NAN; | |
| 4917 // } | |
| 4918 // if (base != -Infinity && exponent == 0.5) { | |
| 4919 // if (base == 0.0) return 0.0; | |
| 4920 // return sqrt(value); | |
| 4921 // } | |
| 4922 XmmRegister base = locs()->in(0).fpu_reg(); | |
| 4923 XmmRegister exp = locs()->in(1).fpu_reg(); | |
| 4924 XmmRegister result = locs()->out(0).fpu_reg(); | |
| 4925 Register temp = locs()->temp(kObjectTempIndex).reg(); | |
| 4926 XmmRegister zero_temp = locs()->temp(kDoubleTempIndex).fpu_reg(); | |
| 4927 | |
| 4928 Label try_sqrt, check_base, return_nan; | |
| 4929 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0))); | |
| 4930 __ movsd(zero_temp, FieldAddress(temp, Double::value_offset())); | |
| 4931 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1))); | |
| 4932 __ movsd(result, FieldAddress(temp, Double::value_offset())); | |
| 4933 | |
| 4934 // exponent == 0.0 -> return 1.0; | |
| 4935 __ comisd(exp, zero_temp); | |
| 4936 __ j(PARITY_EVEN, &check_base, Assembler::kNearJump); | |
| 4937 __ j(EQUAL, &skip_call, Assembler::kNearJump); // 'result' is 1.0. | |
| 4938 | |
| 4939 __ Bind(&check_base); | |
| 4940 // Note: 'exp' could be NaN. | |
| 4941 | |
| 4942 // base == 1.0 -> return 1.0; | |
| 4943 __ comisd(base, result); | |
| 4944 __ j(PARITY_EVEN, &return_nan, Assembler::kNearJump); | |
| 4945 __ j(EQUAL, &skip_call, Assembler::kNearJump); | |
| 4946 // Note: 'base' could be NaN. | |
| 4947 __ comisd(exp, base); | |
| 4948 // Neither 'exp' nor 'base' is NaN. | |
| 4949 __ j(PARITY_ODD, &try_sqrt, Assembler::kNearJump); | |
| 4950 // Return NaN. | |
| 4951 __ Bind(&return_nan); | |
| 4952 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(NAN))); | |
| 4953 __ movsd(result, FieldAddress(temp, Double::value_offset())); | |
| 4954 __ jmp(&skip_call); | |
| 4955 | |
| 4956 Label do_pow, return_zero; | |
| 4957 __ Bind(&try_sqrt); | |
| 4958 // Before calling pow, check if we could use sqrt instead of pow. | |
| 4959 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(-INFINITY))); | |
| 4960 __ movsd(result, FieldAddress(temp, Double::value_offset())); | |
| 4961 // base == -Infinity -> call pow; | |
| 4962 __ comisd(base, result); | |
| 4963 __ j(EQUAL, &do_pow, Assembler::kNearJump); | |
| 4964 | |
| 4965 // exponent == 0.5 ? | |
| 4966 __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0.5))); | |
| 4967 __ movsd(result, FieldAddress(temp, Double::value_offset())); | |
| 4968 __ comisd(exp, result); | |
| 4969 __ j(NOT_EQUAL, &do_pow, Assembler::kNearJump); | |
| 4970 | |
| 4971 // base == 0 -> return 0; | |
| 4972 __ comisd(base, zero_temp); | |
| 4973 __ j(EQUAL, &return_zero, Assembler::kNearJump); | |
| 4974 | |
| 4975 __ sqrtsd(result, base); | |
| 4976 __ jmp(&skip_call, Assembler::kNearJump); | |
| 4977 | |
| 4978 __ Bind(&return_zero); | |
| 4979 __ movsd(result, zero_temp); | |
| 4980 __ jmp(&skip_call); | |
| 4981 | |
| 4982 __ Bind(&do_pow); | |
| 4983 } | |
| 4984 | 5047 |
| 4985 __ CallRuntime(TargetFunction(), InputCount()); | 5048 __ CallRuntime(TargetFunction(), InputCount()); |
| 4986 __ fstpl(Address(ESP, 0)); | 5049 __ fstpl(Address(ESP, 0)); |
| 4987 __ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0)); | 5050 __ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0)); |
| 4988 __ Bind(&skip_call); | |
| 4989 // Restore ESP. | 5051 // Restore ESP. |
| 4990 __ movl(ESP, locs()->temp(kSavedSpTempIndex).reg()); | 5052 __ movl(ESP, locs()->temp(kSavedSpTempIndex).reg()); |
| 4991 } | 5053 } |
| 4992 | 5054 |
| 4993 | 5055 |
| 4994 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { | 5056 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { |
| 4995 // Only use this instruction in optimized code. | 5057 // Only use this instruction in optimized code. |
| 4996 ASSERT(opt); | 5058 ASSERT(opt); |
| 4997 const intptr_t kNumInputs = 1; | 5059 const intptr_t kNumInputs = 1; |
| 4998 LocationSummary* summary = | 5060 LocationSummary* summary = |
| (...skipping 1029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6028 PcDescriptors::kOther, | 6090 PcDescriptors::kOther, |
| 6029 locs()); | 6091 locs()); |
| 6030 __ Drop(ArgumentCount()); // Discard arguments. | 6092 __ Drop(ArgumentCount()); // Discard arguments. |
| 6031 } | 6093 } |
| 6032 | 6094 |
| 6033 } // namespace dart | 6095 } // namespace dart |
| 6034 | 6096 |
| 6035 #undef __ | 6097 #undef __ |
| 6036 | 6098 |
| 6037 #endif // defined TARGET_ARCH_IA32 | 6099 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |