| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 5080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5091 ASSERT((InputCount() == 1) || (InputCount() == 2)); | 5091 ASSERT((InputCount() == 1) || (InputCount() == 2)); |
| 5092 const intptr_t kNumTemps = 0; | 5092 const intptr_t kNumTemps = 0; |
| 5093 LocationSummary* result = | 5093 LocationSummary* result = |
| 5094 new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall); | 5094 new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall); |
| 5095 result->set_in(0, Location::FpuRegisterLocation(Q0)); | 5095 result->set_in(0, Location::FpuRegisterLocation(Q0)); |
| 5096 if (InputCount() == 2) { | 5096 if (InputCount() == 2) { |
| 5097 result->set_in(1, Location::FpuRegisterLocation(Q1)); | 5097 result->set_in(1, Location::FpuRegisterLocation(Q1)); |
| 5098 } | 5098 } |
| 5099 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { | 5099 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { |
| 5100 result->AddTemp(Location::RegisterLocation(R2)); | 5100 result->AddTemp(Location::RegisterLocation(R2)); |
| 5101 result->AddTemp(Location::FpuRegisterLocation(Q2)); | |
| 5102 } | 5101 } |
| 5103 #if !defined(ARM_FLOAT_ABI_HARD) | 5102 #if !defined(ARM_FLOAT_ABI_HARD) |
| 5104 result->AddTemp(Location::RegisterLocation(R0)); | 5103 result->AddTemp(Location::RegisterLocation(R0)); |
| 5105 result->AddTemp(Location::RegisterLocation(R1)); | 5104 result->AddTemp(Location::RegisterLocation(R1)); |
| 5106 // Check if R2 is already added. | 5105 // Check if R2 is already added. |
| 5107 if (recognized_kind() != MethodRecognizer::kMathDoublePow) { | 5106 if (recognized_kind() != MethodRecognizer::kMathDoublePow) { |
| 5108 result->AddTemp(Location::RegisterLocation(R2)); | 5107 result->AddTemp(Location::RegisterLocation(R2)); |
| 5109 } | 5108 } |
| 5110 result->AddTemp(Location::RegisterLocation(R3)); | 5109 result->AddTemp(Location::RegisterLocation(R3)); |
| 5111 #endif | 5110 #endif |
| 5112 result->set_out(0, Location::FpuRegisterLocation(Q0)); | 5111 result->set_out(0, Location::FpuRegisterLocation(Q0)); |
| 5113 return result; | 5112 return result; |
| 5114 } | 5113 } |
| 5115 | 5114 |
| 5116 | 5115 |
| 5116 // Pseudo code: |
| 5117 // if (exponent == 0.0) return 1.0; |
| 5118 // // Speed up simple cases. |
| 5119 // if (exponent == 1.0) return base; |
| 5120 // if (exponent == 2.0) return base * base; |
| 5121 // if (exponent == 3.0) return base * base * base; |
| 5122 // if (base == 1.0) return 1.0; |
| 5123 // if (base.isNaN || exponent.isNaN) { |
| 5124 // return double.NAN; |
| 5125 // } |
| 5126 // if (base != -Infinity && exponent == 0.5) { |
| 5127 // if (base == 0.0) return 0.0; |
| 5128 // return sqrt(value); |
| 5129 // } |
| 5130 // TODO(srdjan): Move into a stub? |
| 5131 static void InvokeDoublePow(FlowGraphCompiler* compiler, |
| 5132 InvokeMathCFunctionInstr* instr) { |
| 5133 ASSERT(instr->recognized_kind() == MethodRecognizer::kMathDoublePow); |
| 5134 const intptr_t kInputCount = 2; |
| 5135 ASSERT(instr->InputCount() == kInputCount); |
| 5136 LocationSummary* locs = instr->locs(); |
| 5137 |
| 5138 const DRegister base = EvenDRegisterOf(locs->in(0).fpu_reg()); |
| 5139 const DRegister exp = EvenDRegisterOf(locs->in(1).fpu_reg()); |
| 5140 const DRegister result = EvenDRegisterOf(locs->out(0).fpu_reg()); |
| 5141 const Register temp = locs->temp(0).reg(); |
| 5142 const DRegister saved_base = OddDRegisterOf(locs->in(0).fpu_reg()); |
| 5143 ASSERT((base == result) && (result != saved_base)); |
| 5144 |
| 5145 Label skip_call, try_sqrt, check_base, return_nan; |
| 5146 __ vmovd(saved_base, base); |
| 5147 __ LoadDImmediate(result, 1.0, temp); |
| 5148 // exponent == 0.0 -> return 1.0; |
| 5149 __ vcmpdz(exp); |
| 5150 __ vmstat(); |
| 5151 __ b(&check_base, VS); // NaN -> check base. |
| 5152 __ b(&skip_call, EQ); // exp is 0.0, result is 1.0. |
| 5153 |
| 5154 // exponent == 1.0 ? |
| 5155 __ vcmpd(exp, result); |
| 5156 __ vmstat(); |
| 5157 Label return_base; |
| 5158 __ b(&return_base, EQ); |
| 5159 |
| 5160 // exponent == 2.0 ? |
| 5161 __ LoadDImmediate(DTMP, 2.0, temp); |
| 5162 __ vcmpd(exp, DTMP); |
| 5163 __ vmstat(); |
| 5164 Label return_base_times_2; |
| 5165 __ b(&return_base_times_2, EQ); |
| 5166 |
| 5167 // exponent == 3.0 ? |
| 5168 __ LoadDImmediate(DTMP, 3.0, temp); |
| 5169 __ vcmpd(exp, DTMP); |
| 5170 __ vmstat(); |
| 5171 __ b(&check_base, NE); |
| 5172 |
| 5173 // base_times_3. |
| 5174 __ vmuld(result, saved_base, saved_base); |
| 5175 __ vmuld(result, result, saved_base); |
| 5176 __ b(&skip_call); |
| 5177 |
| 5178 __ Bind(&return_base); |
| 5179 __ vmovd(result, saved_base); |
| 5180 __ b(&skip_call); |
| 5181 |
| 5182 __ Bind(&return_base_times_2); |
| 5183 __ vmuld(result, saved_base, saved_base); |
| 5184 __ b(&skip_call); |
| 5185 |
| 5186 __ Bind(&check_base); |
| 5187 // Note: 'exp' could be NaN. |
| 5188 // base == 1.0 -> return 1.0; |
| 5189 __ vcmpd(saved_base, result); |
| 5190 __ vmstat(); |
| 5191 __ b(&return_nan, VS); |
| 5192 __ b(&skip_call, EQ); // base is 1.0, result is 1.0. |
| 5193 |
| 5194 __ vcmpd(saved_base, exp); |
| 5195 __ b(&try_sqrt, VC); // // Neither 'exp' nor 'base' is NaN. |
| 5196 |
| 5197 __ Bind(&return_nan); |
| 5198 __ LoadDImmediate(result, NAN, temp); |
| 5199 __ b(&skip_call); |
| 5200 |
| 5201 Label do_pow, return_zero; |
| 5202 __ Bind(&try_sqrt); |
| 5203 |
| 5204 // Before calling pow, check if we could use sqrt instead of pow. |
| 5205 __ LoadDImmediate(result, -INFINITY, temp); |
| 5206 |
| 5207 // base == -Infinity -> call pow; |
| 5208 __ vcmpd(saved_base, result); |
| 5209 __ b(&do_pow, EQ); |
| 5210 |
| 5211 // exponent == 0.5 ? |
| 5212 __ LoadDImmediate(result, 0.5, temp); |
| 5213 __ vcmpd(exp, result); |
| 5214 __ b(&do_pow, NE); |
| 5215 |
| 5216 // base == 0 -> return 0; |
| 5217 __ vcmpdz(base); |
| 5218 __ b(&return_zero, EQ); |
| 5219 |
| 5220 __ vsqrtd(result, saved_base); |
| 5221 __ b(&skip_call); |
| 5222 |
| 5223 __ Bind(&return_zero); |
| 5224 __ LoadDImmediate(result, 0.0, temp); |
| 5225 __ b(&skip_call); |
| 5226 |
| 5227 __ Bind(&do_pow); |
| 5228 __ vmovd(base, saved_base); // Restore base. |
| 5229 |
| 5230 // Args must be in D0 and D1, so move arg from Q1(== D3:D2) to D1. |
| 5231 __ vmovd(D1, D2); |
| 5232 #if defined(ARM_FLOAT_ABI_HARD) |
| 5233 __ CallRuntime(instr->TargetFunction(), kInputCount); |
| 5234 #else |
| 5235 // If the ABI is not "hardfp", then we have to move the double arguments |
| 5236 // to the integer registers, and take the results from the integer |
| 5237 // registers. |
| 5238 __ vmovrrd(R0, R1, D0); |
| 5239 __ vmovrrd(R2, R3, D1); |
| 5240 __ CallRuntime(instr->TargetFunction(), kInputCount); |
| 5241 __ vmovdrr(D0, R0, R1); |
| 5242 __ vmovdrr(D1, R2, R3); |
| 5243 #endif |
| 5244 __ Bind(&skip_call); |
| 5245 } |
| 5246 |
| 5247 |
| 5117 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5248 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5118 // For pow-function return NaN if exponent is NaN. | |
| 5119 Label skip_call; | |
| 5120 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { | 5249 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { |
| 5121 // Pseudo code: | 5250 InvokeDoublePow(compiler, this); |
| 5122 // if (exponent == 0.0) return 1.0; | 5251 return; |
| 5123 // if (base == 1.0) return 1.0; | |
| 5124 // if (base.isNaN || exponent.isNaN) { | |
| 5125 // return double.NAN; | |
| 5126 // } | |
| 5127 // if (base != -Infinity && exponent == 0.5) { | |
| 5128 // if (base == 0.0) return 0.0; | |
| 5129 // return sqrt(value); | |
| 5130 // } | |
| 5131 const DRegister base = EvenDRegisterOf(locs()->in(0).fpu_reg()); | |
| 5132 const DRegister exp = EvenDRegisterOf(locs()->in(1).fpu_reg()); | |
| 5133 const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg()); | |
| 5134 const Register temp = locs()->temp(0).reg(); | |
| 5135 const DRegister saved_base = EvenDRegisterOf(locs()->temp(1).fpu_reg()); | |
| 5136 ASSERT((base == result) && (result != saved_base)); | |
| 5137 | |
| 5138 Label try_sqrt, check_base, return_nan; | |
| 5139 __ vmovd(saved_base, base); | |
| 5140 __ LoadDImmediate(DTMP, 0.0, temp); | |
| 5141 __ LoadDImmediate(result, 1.0, temp); | |
| 5142 // exponent == 0.0 -> return 1.0; | |
| 5143 __ vcmpd(exp, DTMP); | |
| 5144 __ vmstat(); | |
| 5145 __ b(&check_base, VS); // NaN -> check base. | |
| 5146 __ b(&skip_call, EQ); // exp is 0.0, result is 1.0. | |
| 5147 | |
| 5148 __ Bind(&check_base); | |
| 5149 // Note: 'exp' could be NaN. | |
| 5150 // base == 1.0 -> return 1.0; | |
| 5151 __ vcmpd(saved_base, result); | |
| 5152 __ vmstat(); | |
| 5153 __ b(&return_nan, VS); | |
| 5154 __ b(&skip_call, EQ); // base is 1.0, result is 1.0. | |
| 5155 | |
| 5156 __ vcmpd(saved_base, exp); | |
| 5157 __ b(&try_sqrt, VC); // // Neither 'exp' nor 'base' is NaN. | |
| 5158 | |
| 5159 __ Bind(&return_nan); | |
| 5160 __ LoadDImmediate(result, NAN, temp); | |
| 5161 __ b(&skip_call); | |
| 5162 | |
| 5163 Label do_pow, return_zero; | |
| 5164 __ Bind(&try_sqrt); | |
| 5165 | |
| 5166 // Before calling pow, check if we could use sqrt instead of pow. | |
| 5167 __ LoadDImmediate(result, -INFINITY, temp); | |
| 5168 | |
| 5169 // base == -Infinity -> call pow; | |
| 5170 __ vcmpd(saved_base, result); | |
| 5171 __ b(&do_pow, EQ); | |
| 5172 | |
| 5173 // exponent == 0.5 ? | |
| 5174 __ LoadDImmediate(result, 0.5, temp); | |
| 5175 __ vcmpd(exp, result); | |
| 5176 __ b(&do_pow, NE); | |
| 5177 | |
| 5178 // base == 0 -> return 0; | |
| 5179 __ vcmpd(base, DTMP); | |
| 5180 __ b(&return_zero, EQ); | |
| 5181 | |
| 5182 __ vsqrtd(result, saved_base); | |
| 5183 __ b(&skip_call); | |
| 5184 | |
| 5185 __ Bind(&return_zero); | |
| 5186 __ vmovd(result, DTMP); | |
| 5187 __ b(&skip_call); | |
| 5188 | |
| 5189 __ Bind(&do_pow); | |
| 5190 __ vmovd(base, saved_base); // Restore base. | |
| 5191 } | 5252 } |
| 5192 | 5253 |
| 5193 if (InputCount() == 2) { | 5254 if (InputCount() == 2) { |
| 5194 // Args must be in D0 and D1, so move arg from Q1(== D3:D2) to D1. | 5255 // Args must be in D0 and D1, so move arg from Q1(== D3:D2) to D1. |
| 5195 __ vmovd(D1, D2); | 5256 __ vmovd(D1, D2); |
| 5196 } | 5257 } |
| 5197 #if defined(ARM_FLOAT_ABI_HARD) | 5258 #if defined(ARM_FLOAT_ABI_HARD) |
| 5198 __ CallRuntime(TargetFunction(), InputCount()); | 5259 __ CallRuntime(TargetFunction(), InputCount()); |
| 5199 #else | 5260 #else |
| 5200 // If the ABI is not "hardfp", then we have to move the double arguments | 5261 // If the ABI is not "hardfp", then we have to move the double arguments |
| 5201 // to the integer registers, and take the results from the integer | 5262 // to the integer registers, and take the results from the integer |
| 5202 // registers. | 5263 // registers. |
| 5203 __ vmovrrd(R0, R1, D0); | 5264 __ vmovrrd(R0, R1, D0); |
| 5204 __ vmovrrd(R2, R3, D1); | 5265 __ vmovrrd(R2, R3, D1); |
| 5205 __ CallRuntime(TargetFunction(), InputCount()); | 5266 __ CallRuntime(TargetFunction(), InputCount()); |
| 5206 __ vmovdrr(D0, R0, R1); | 5267 __ vmovdrr(D0, R0, R1); |
| 5207 __ vmovdrr(D1, R2, R3); | 5268 __ vmovdrr(D1, R2, R3); |
| 5208 #endif | 5269 #endif |
| 5209 __ Bind(&skip_call); | |
| 5210 } | 5270 } |
| 5211 | 5271 |
| 5212 | 5272 |
| 5213 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { | 5273 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { |
| 5214 // Only use this instruction in optimized code. | 5274 // Only use this instruction in optimized code. |
| 5215 ASSERT(opt); | 5275 ASSERT(opt); |
| 5216 const intptr_t kNumInputs = 1; | 5276 const intptr_t kNumInputs = 1; |
| 5217 LocationSummary* summary = | 5277 LocationSummary* summary = |
| 5218 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); | 5278 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); |
| 5219 if (representation() == kUnboxedDouble) { | 5279 if (representation() == kUnboxedDouble) { |
| (...skipping 863 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6083 compiler->GenerateCall(token_pos(), | 6143 compiler->GenerateCall(token_pos(), |
| 6084 &label, | 6144 &label, |
| 6085 PcDescriptors::kOther, | 6145 PcDescriptors::kOther, |
| 6086 locs()); | 6146 locs()); |
| 6087 __ Drop(ArgumentCount()); // Discard arguments. | 6147 __ Drop(ArgumentCount()); // Discard arguments. |
| 6088 } | 6148 } |
| 6089 | 6149 |
| 6090 } // namespace dart | 6150 } // namespace dart |
| 6091 | 6151 |
| 6092 #endif // defined TARGET_ARCH_ARM | 6152 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |