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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
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 2133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2144 intptr_t threshold = | 2144 intptr_t threshold = |
2145 FLAG_optimization_counter_threshold * (loop_depth() + 1); | 2145 FLAG_optimization_counter_threshold * (loop_depth() + 1); |
2146 __ cmpq(FieldAddress(temp, Function::usage_counter_offset()), | 2146 __ cmpq(FieldAddress(temp, Function::usage_counter_offset()), |
2147 Immediate(threshold)); | 2147 Immediate(threshold)); |
2148 __ j(GREATER_EQUAL, slow_path->entry_label()); | 2148 __ j(GREATER_EQUAL, slow_path->entry_label()); |
2149 } | 2149 } |
2150 __ Bind(slow_path->exit_label()); | 2150 __ Bind(slow_path->exit_label()); |
2151 } | 2151 } |
2152 | 2152 |
2153 | 2153 |
2154 static void Emit54BitOverflowCheck(FlowGraphCompiler* compiler, | 2154 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, |
2155 Label* overflow, | 2155 Label* overflow, |
2156 Register result) { | 2156 Register result) { |
2157 if (FLAG_throw_on_javascript_int_overflow) { | 2157 if (FLAG_throw_on_javascript_int_overflow) { |
2158 ASSERT(overflow != NULL); | 2158 ASSERT(overflow != NULL); |
2159 __ movq(TMP, result); // result is a tagged Smi. | 2159 __ cmpq(result, Immediate(-0x20000000000000)); |
2160 // Bits 55...64 must be all 0 or all 1. (It would be bit 54, but result | 2160 __ j(LESS, overflow); |
2161 // is tagged.) | 2161 __ cmpq(result, Immediate(0x20000000000000)); |
2162 __ shlq(result, Immediate(64 - 55)); | 2162 __ j(GREATER, overflow); |
2163 __ sarq(result, Immediate(64 - 55)); | |
2164 __ cmpq(result, TMP); | |
2165 __ j(NOT_EQUAL, overflow); // 54-bit overflow. | |
2166 __ cmpq(result, Immediate(-0x1FFFFFFFFFFFFFLL - 1)); | |
2167 __ j(EQUAL, overflow); // The most negative 54-bit int is also disallowed. | |
2168 } | 2163 } |
2169 } | 2164 } |
2170 | 2165 |
2171 | 2166 |
2172 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2167 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
2173 BinarySmiOpInstr* shift_left) { | 2168 BinarySmiOpInstr* shift_left) { |
2174 const bool is_truncating = shift_left->is_truncating(); | 2169 const bool is_truncating = shift_left->is_truncating(); |
2175 const LocationSummary& locs = *shift_left->locs(); | 2170 const LocationSummary& locs = *shift_left->locs(); |
2176 Register left = locs.in(0).reg(); | 2171 Register left = locs.in(0).reg(); |
2177 Register result = locs.out().reg(); | 2172 Register result = locs.out().reg(); |
(...skipping 23 matching lines...) Expand all Loading... |
2201 Register temp = locs.temp(0).reg(); | 2196 Register temp = locs.temp(0).reg(); |
2202 __ movq(temp, left); | 2197 __ movq(temp, left); |
2203 __ shlq(left, Immediate(value)); | 2198 __ shlq(left, Immediate(value)); |
2204 __ sarq(left, Immediate(value)); | 2199 __ sarq(left, Immediate(value)); |
2205 __ cmpq(left, temp); | 2200 __ cmpq(left, temp); |
2206 __ j(NOT_EQUAL, deopt); // Overflow. | 2201 __ j(NOT_EQUAL, deopt); // Overflow. |
2207 } | 2202 } |
2208 // Shift for result now we know there is no overflow. | 2203 // Shift for result now we know there is no overflow. |
2209 __ shlq(left, Immediate(value)); | 2204 __ shlq(left, Immediate(value)); |
2210 } | 2205 } |
2211 Emit54BitOverflowCheck(compiler, deopt, result); | 2206 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2212 return; | 2207 return; |
2213 } | 2208 } |
2214 | 2209 |
2215 // Right (locs.in(1)) is not constant. | 2210 // Right (locs.in(1)) is not constant. |
2216 Register right = locs.in(1).reg(); | 2211 Register right = locs.in(1).reg(); |
2217 Range* right_range = shift_left->right()->definition()->range(); | 2212 Range* right_range = shift_left->right()->definition()->range(); |
2218 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2213 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
2219 // TODO(srdjan): Implement code below for is_truncating(). | 2214 // TODO(srdjan): Implement code below for is_truncating(). |
2220 // If left is constant, we know the maximal allowed size for right. | 2215 // If left is constant, we know the maximal allowed size for right. |
2221 const Object& obj = shift_left->left()->BoundConstant(); | 2216 const Object& obj = shift_left->left()->BoundConstant(); |
2222 if (obj.IsSmi()) { | 2217 if (obj.IsSmi()) { |
2223 const intptr_t left_int = Smi::Cast(obj).Value(); | 2218 const intptr_t left_int = Smi::Cast(obj).Value(); |
2224 if (left_int == 0) { | 2219 if (left_int == 0) { |
2225 __ cmpq(right, Immediate(0)); | 2220 __ cmpq(right, Immediate(0)); |
2226 __ j(NEGATIVE, deopt); | 2221 __ j(NEGATIVE, deopt); |
2227 return; | 2222 return; |
2228 } | 2223 } |
2229 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2224 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
2230 const bool right_needs_check = | 2225 const bool right_needs_check = |
2231 (right_range == NULL) || | 2226 (right_range == NULL) || |
2232 !right_range->IsWithin(0, max_right - 1); | 2227 !right_range->IsWithin(0, max_right - 1); |
2233 if (right_needs_check) { | 2228 if (right_needs_check) { |
2234 __ cmpq(right, | 2229 __ cmpq(right, |
2235 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); | 2230 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); |
2236 __ j(ABOVE_EQUAL, deopt); | 2231 __ j(ABOVE_EQUAL, deopt); |
2237 } | 2232 } |
2238 __ SmiUntag(right); | 2233 __ SmiUntag(right); |
2239 __ shlq(left, right); | 2234 __ shlq(left, right); |
2240 } | 2235 } |
2241 Emit54BitOverflowCheck(compiler, deopt, result); | 2236 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2242 return; | 2237 return; |
2243 } | 2238 } |
2244 | 2239 |
2245 const bool right_needs_check = | 2240 const bool right_needs_check = |
2246 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | 2241 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
2247 ASSERT(right == RCX); // Count must be in RCX | 2242 ASSERT(right == RCX); // Count must be in RCX |
2248 if (is_truncating) { | 2243 if (is_truncating) { |
2249 if (right_needs_check) { | 2244 if (right_needs_check) { |
2250 const bool right_may_be_negative = | 2245 const bool right_may_be_negative = |
2251 (right_range == NULL) || | 2246 (right_range == NULL) || |
(...skipping 30 matching lines...) Expand all Loading... |
2282 __ movq(temp, left); | 2277 __ movq(temp, left); |
2283 __ SmiUntag(right); | 2278 __ SmiUntag(right); |
2284 // Overflow test (preserve temp and right); | 2279 // Overflow test (preserve temp and right); |
2285 __ shlq(left, right); | 2280 __ shlq(left, right); |
2286 __ sarq(left, right); | 2281 __ sarq(left, right); |
2287 __ cmpq(left, temp); | 2282 __ cmpq(left, temp); |
2288 __ j(NOT_EQUAL, deopt); // Overflow. | 2283 __ j(NOT_EQUAL, deopt); // Overflow. |
2289 // Shift for result now we know there is no overflow. | 2284 // Shift for result now we know there is no overflow. |
2290 __ shlq(left, right); | 2285 __ shlq(left, right); |
2291 } | 2286 } |
2292 Emit54BitOverflowCheck(compiler, deopt, result); | 2287 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2293 } | 2288 } |
2294 | 2289 |
2295 | 2290 |
2296 static bool CanBeImmediate(const Object& constant) { | 2291 static bool CanBeImmediate(const Object& constant) { |
2297 return constant.IsSmi() && | 2292 return constant.IsSmi() && |
2298 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); | 2293 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); |
2299 } | 2294 } |
2300 | 2295 |
2301 | 2296 |
2302 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2297 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2481 | 2476 |
2482 __ sarq(left, Immediate(value)); | 2477 __ sarq(left, Immediate(value)); |
2483 __ SmiTag(left); | 2478 __ SmiTag(left); |
2484 break; | 2479 break; |
2485 } | 2480 } |
2486 | 2481 |
2487 default: | 2482 default: |
2488 UNREACHABLE(); | 2483 UNREACHABLE(); |
2489 break; | 2484 break; |
2490 } | 2485 } |
2491 Emit54BitOverflowCheck(compiler, deopt, result); | 2486 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2492 return; | 2487 return; |
2493 } // locs()->in(1).IsConstant(). | 2488 } // locs()->in(1).IsConstant(). |
2494 | 2489 |
2495 | 2490 |
2496 if (locs()->in(1).IsStackSlot()) { | 2491 if (locs()->in(1).IsStackSlot()) { |
2497 const Address& right = locs()->in(1).ToStackSlotAddress(); | 2492 const Address& right = locs()->in(1).ToStackSlotAddress(); |
2498 switch (op_kind()) { | 2493 switch (op_kind()) { |
2499 case Token::kADD: { | 2494 case Token::kADD: { |
2500 __ addq(left, right); | 2495 __ addq(left, right); |
2501 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2496 if (deopt != NULL) __ j(OVERFLOW, deopt); |
(...skipping 22 matching lines...) Expand all Loading... |
2524 } | 2519 } |
2525 case Token::kBIT_XOR: { | 2520 case Token::kBIT_XOR: { |
2526 // No overflow check. | 2521 // No overflow check. |
2527 __ xorq(left, right); | 2522 __ xorq(left, right); |
2528 break; | 2523 break; |
2529 } | 2524 } |
2530 default: | 2525 default: |
2531 UNREACHABLE(); | 2526 UNREACHABLE(); |
2532 break; | 2527 break; |
2533 } | 2528 } |
2534 Emit54BitOverflowCheck(compiler, deopt, result); | 2529 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2535 return; | 2530 return; |
2536 } // locs()->in(1).IsStackSlot(). | 2531 } // locs()->in(1).IsStackSlot(). |
2537 | 2532 |
2538 // if locs()->in(1).IsRegister. | 2533 // if locs()->in(1).IsRegister. |
2539 Register right = locs()->in(1).reg(); | 2534 Register right = locs()->in(1).reg(); |
2540 switch (op_kind()) { | 2535 switch (op_kind()) { |
2541 case Token::kADD: { | 2536 case Token::kADD: { |
2542 __ addq(left, right); | 2537 __ addq(left, right); |
2543 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2538 if (deopt != NULL) __ j(OVERFLOW, deopt); |
2544 break; | 2539 break; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2654 case Token::kAND: { | 2649 case Token::kAND: { |
2655 // Flow graph builder has dissected this operation to guarantee correct | 2650 // Flow graph builder has dissected this operation to guarantee correct |
2656 // behavior (short-circuit evaluation). | 2651 // behavior (short-circuit evaluation). |
2657 UNREACHABLE(); | 2652 UNREACHABLE(); |
2658 break; | 2653 break; |
2659 } | 2654 } |
2660 default: | 2655 default: |
2661 UNREACHABLE(); | 2656 UNREACHABLE(); |
2662 break; | 2657 break; |
2663 } | 2658 } |
2664 Emit54BitOverflowCheck(compiler, deopt, result); | 2659 EmitJavascriptOverflowCheck(compiler, deopt, result); |
2665 } | 2660 } |
2666 | 2661 |
2667 | 2662 |
2668 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { | 2663 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { |
2669 intptr_t left_cid = left()->Type()->ToCid(); | 2664 intptr_t left_cid = left()->Type()->ToCid(); |
2670 intptr_t right_cid = right()->Type()->ToCid(); | 2665 intptr_t right_cid = right()->Type()->ToCid(); |
2671 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 2666 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
2672 const intptr_t kNumInputs = 2; | 2667 const intptr_t kNumInputs = 2; |
2673 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); | 2668 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); |
2674 const intptr_t kNumTemps = need_temp ? 1 : 0; | 2669 const intptr_t kNumTemps = need_temp ? 1 : 0; |
(...skipping 1157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3832 | 3827 |
3833 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3828 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3834 Register value = locs()->in(0).reg(); | 3829 Register value = locs()->in(0).reg(); |
3835 ASSERT(value == locs()->out().reg()); | 3830 ASSERT(value == locs()->out().reg()); |
3836 switch (op_kind()) { | 3831 switch (op_kind()) { |
3837 case Token::kNEGATE: { | 3832 case Token::kNEGATE: { |
3838 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 3833 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
3839 kDeoptUnaryOp); | 3834 kDeoptUnaryOp); |
3840 __ negq(value); | 3835 __ negq(value); |
3841 __ j(OVERFLOW, deopt); | 3836 __ j(OVERFLOW, deopt); |
3842 Emit54BitOverflowCheck(compiler, deopt, value); | 3837 EmitJavascriptOverflowCheck(compiler, deopt, value); |
3843 break; | 3838 break; |
3844 } | 3839 } |
3845 case Token::kBIT_NOT: | 3840 case Token::kBIT_NOT: |
3846 __ notq(value); | 3841 __ notq(value); |
3847 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 3842 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
3848 break; | 3843 break; |
3849 default: | 3844 default: |
3850 UNREACHABLE(); | 3845 UNREACHABLE(); |
3851 } | 3846 } |
3852 } | 3847 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3893 ASSERT(result != temp); | 3888 ASSERT(result != temp); |
3894 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); | 3889 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); |
3895 __ cvttsd2siq(result, value_double); | 3890 __ cvttsd2siq(result, value_double); |
3896 // Overflow is signalled with minint. | 3891 // Overflow is signalled with minint. |
3897 Label do_call, done; | 3892 Label do_call, done; |
3898 // Check for overflow and that it fits into Smi. | 3893 // Check for overflow and that it fits into Smi. |
3899 __ movq(temp, result); | 3894 __ movq(temp, result); |
3900 __ shlq(temp, Immediate(1)); | 3895 __ shlq(temp, Immediate(1)); |
3901 __ j(OVERFLOW, &do_call, Assembler::kNearJump); | 3896 __ j(OVERFLOW, &do_call, Assembler::kNearJump); |
3902 __ SmiTag(result); | 3897 __ SmiTag(result); |
3903 Emit54BitOverflowCheck(compiler, &do_call, result); | 3898 EmitJavascriptOverflowCheck(compiler, &do_call, result); |
3904 __ jmp(&done); | 3899 __ jmp(&done); |
3905 __ Bind(&do_call); | 3900 __ Bind(&do_call); |
3906 ASSERT(instance_call()->HasICData()); | 3901 ASSERT(instance_call()->HasICData()); |
3907 const ICData& ic_data = *instance_call()->ic_data(); | 3902 const ICData& ic_data = *instance_call()->ic_data(); |
3908 ASSERT((ic_data.NumberOfChecks() == 1)); | 3903 ASSERT((ic_data.NumberOfChecks() == 1)); |
3909 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 3904 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
3910 | 3905 |
3911 const intptr_t kNumberOfArguments = 1; | 3906 const intptr_t kNumberOfArguments = 1; |
3912 __ pushq(value_obj); | 3907 __ pushq(value_obj); |
3913 compiler->GenerateStaticCall(deopt_id(), | 3908 compiler->GenerateStaticCall(deopt_id(), |
(...skipping 25 matching lines...) Expand all Loading... |
3939 Register temp = locs()->temp(0).reg(); | 3934 Register temp = locs()->temp(0).reg(); |
3940 | 3935 |
3941 __ cvttsd2siq(result, value); | 3936 __ cvttsd2siq(result, value); |
3942 // Overflow is signalled with minint. | 3937 // Overflow is signalled with minint. |
3943 Label do_call, done; | 3938 Label do_call, done; |
3944 // Check for overflow and that it fits into Smi. | 3939 // Check for overflow and that it fits into Smi. |
3945 __ movq(temp, result); | 3940 __ movq(temp, result); |
3946 __ shlq(temp, Immediate(1)); | 3941 __ shlq(temp, Immediate(1)); |
3947 __ j(OVERFLOW, deopt); | 3942 __ j(OVERFLOW, deopt); |
3948 __ SmiTag(result); | 3943 __ SmiTag(result); |
3949 Emit54BitOverflowCheck(compiler, deopt, result); | 3944 EmitJavascriptOverflowCheck(compiler, deopt, result); |
3950 } | 3945 } |
3951 | 3946 |
3952 | 3947 |
3953 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { | 3948 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { |
3954 const intptr_t kNumInputs = 1; | 3949 const intptr_t kNumInputs = 1; |
3955 const intptr_t kNumTemps = 0; | 3950 const intptr_t kNumTemps = 0; |
3956 LocationSummary* result = | 3951 LocationSummary* result = |
3957 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3952 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
3958 result->set_in(0, Location::RequiresFpuRegister()); | 3953 result->set_in(0, Location::RequiresFpuRegister()); |
3959 result->set_out(Location::RequiresFpuRegister()); | 3954 result->set_out(Location::RequiresFpuRegister()); |
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4549 PcDescriptors::kOther, | 4544 PcDescriptors::kOther, |
4550 locs()); | 4545 locs()); |
4551 __ Drop(2); // Discard type arguments and receiver. | 4546 __ Drop(2); // Discard type arguments and receiver. |
4552 } | 4547 } |
4553 | 4548 |
4554 } // namespace dart | 4549 } // namespace dart |
4555 | 4550 |
4556 #undef __ | 4551 #undef __ |
4557 | 4552 |
4558 #endif // defined TARGET_ARCH_X64 | 4553 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |