Chromium Code Reviews| 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 "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 2169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2180 | 2180 |
| 2181 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2181 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2182 const intptr_t kNumInputs = 2; | 2182 const intptr_t kNumInputs = 2; |
| 2183 | 2183 |
| 2184 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2184 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2185 if ((right_constant != NULL) && | 2185 if ((right_constant != NULL) && |
| 2186 (op_kind() != Token::kTRUNCDIV) && | 2186 (op_kind() != Token::kTRUNCDIV) && |
| 2187 (op_kind() != Token::kSHL) && | 2187 (op_kind() != Token::kSHL) && |
| 2188 (op_kind() != Token::kMUL) && | 2188 (op_kind() != Token::kMUL) && |
| 2189 (op_kind() != Token::kMOD) && | 2189 (op_kind() != Token::kMOD) && |
| 2190 (op_kind() != Token::kTRUNCDIVMOD) && | |
| 2190 CanBeImmediate(right_constant->value())) { | 2191 CanBeImmediate(right_constant->value())) { |
| 2191 const intptr_t kNumTemps = 0; | 2192 const intptr_t kNumTemps = 0; |
| 2192 LocationSummary* summary = | 2193 LocationSummary* summary = |
| 2193 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2194 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2194 summary->set_in(0, Location::RequiresRegister()); | 2195 summary->set_in(0, Location::RequiresRegister()); |
| 2195 summary->set_in(1, Location::Constant(right_constant->value())); | 2196 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2196 summary->set_out(Location::SameAsFirstInput()); | 2197 summary->set_out(Location::SameAsFirstInput()); |
| 2197 return summary; | 2198 return summary; |
| 2198 } | 2199 } |
| 2199 | 2200 |
| 2200 if (op_kind() == Token::kTRUNCDIV) { | 2201 if (op_kind() == Token::kTRUNCDIV) { |
| 2201 const intptr_t kNumTemps = 1; | 2202 const intptr_t kNumTemps = 1; |
| 2202 LocationSummary* summary = | 2203 LocationSummary* summary = |
| 2203 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2204 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2204 if (RightIsPowerOfTwoConstant()) { | 2205 if (RightIsPowerOfTwoConstant()) { |
| 2205 summary->set_in(0, Location::RequiresRegister()); | 2206 summary->set_in(0, Location::RequiresRegister()); |
| 2206 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2207 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2207 summary->set_in(1, Location::Constant(right_constant->value())); | 2208 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2208 summary->set_temp(0, Location::RequiresRegister()); | 2209 summary->set_temp(0, Location::RequiresRegister()); |
| 2209 summary->set_out(Location::SameAsFirstInput()); | 2210 summary->set_out(Location::SameAsFirstInput()); |
| 2210 } else { | 2211 } else { |
| 2211 // Both inputs must be writable because they will be untagged. | 2212 // Both inputs must be writable because they will be untagged. |
| 2212 summary->set_in(0, Location::RegisterLocation(RAX)); | 2213 summary->set_in(0, Location::RegisterLocation(RAX)); |
| 2213 summary->set_in(1, Location::WritableRegister()); | 2214 summary->set_in(1, Location::WritableRegister()); |
| 2214 summary->set_out(Location::SameAsFirstInput()); | 2215 summary->set_out(Location::SameAsFirstInput()); |
| 2215 // Will be used for sign extension and division. | 2216 // Will be used for sign extension and division. |
| 2216 summary->set_temp(0, Location::RegisterLocation(RDX)); | 2217 summary->set_temp(0, Location::RegisterLocation(RDX)); |
| 2217 } | 2218 } |
| 2218 return summary; | 2219 return summary; |
| 2220 } else if (op_kind() == Token::kTRUNCDIVMOD) { | |
| 2221 const intptr_t kNumTemps = 1; | |
| 2222 LocationSummary* summary = | |
| 2223 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 2224 // Both inputs must be writable because they will be untagged. | |
| 2225 summary->set_in(0, Location::RegisterLocation(RAX)); | |
| 2226 summary->set_in(1, Location::WritableRegister()); | |
| 2227 summary->set_out(Location::RequiresRegister()); | |
| 2228 // Will be used for sign extension and division. | |
| 2229 summary->set_temp(0, Location::RegisterLocation(RDX)); | |
| 2230 return summary; | |
| 2219 } else if (op_kind() == Token::kMOD) { | 2231 } else if (op_kind() == Token::kMOD) { |
| 2220 const intptr_t kNumTemps = 1; | 2232 const intptr_t kNumTemps = 1; |
| 2221 LocationSummary* summary = | 2233 LocationSummary* summary = |
| 2222 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2234 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2223 // Both inputs must be writable because they will be untagged. | 2235 // Both inputs must be writable because they will be untagged. |
| 2224 summary->set_in(0, Location::RegisterLocation(RDX)); | 2236 summary->set_in(0, Location::RegisterLocation(RDX)); |
| 2225 summary->set_in(1, Location::WritableRegister()); | 2237 summary->set_in(1, Location::WritableRegister()); |
| 2226 summary->set_out(Location::SameAsFirstInput()); | 2238 summary->set_out(Location::SameAsFirstInput()); |
| 2227 // Will be used for sign extension and division. | 2239 // Will be used for sign extension and division. |
| 2228 summary->set_temp(0, Location::RegisterLocation(RAX)); | 2240 summary->set_temp(0, Location::RegisterLocation(RAX)); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2264 | 2276 |
| 2265 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2277 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2266 if (op_kind() == Token::kSHL) { | 2278 if (op_kind() == Token::kSHL) { |
| 2267 EmitSmiShiftLeft(compiler, this); | 2279 EmitSmiShiftLeft(compiler, this); |
| 2268 return; | 2280 return; |
| 2269 } | 2281 } |
| 2270 | 2282 |
| 2271 ASSERT(!is_truncating()); | 2283 ASSERT(!is_truncating()); |
| 2272 Register left = locs()->in(0).reg(); | 2284 Register left = locs()->in(0).reg(); |
| 2273 Register result = locs()->out().reg(); | 2285 Register result = locs()->out().reg(); |
| 2274 ASSERT(left == result); | 2286 // DIVMOD is different. |
| 2287 ASSERT((op_kind() == Token::kTRUNCDIVMOD) || (left == result)); | |
| 2275 Label* deopt = NULL; | 2288 Label* deopt = NULL; |
| 2276 if (CanDeoptimize()) { | 2289 if (CanDeoptimize()) { |
| 2277 deopt = compiler->AddDeoptStub(deopt_id(), | 2290 deopt = compiler->AddDeoptStub(deopt_id(), |
| 2278 kDeoptBinarySmiOp); | 2291 kDeoptBinarySmiOp); |
| 2279 } | 2292 } |
| 2280 | 2293 |
| 2281 if (locs()->in(1).IsConstant()) { | 2294 if (locs()->in(1).IsConstant()) { |
| 2282 const Object& constant = locs()->in(1).constant(); | 2295 const Object& constant = locs()->in(1).constant(); |
| 2283 ASSERT(constant.IsSmi()); | 2296 ASSERT(constant.IsSmi()); |
| 2284 const int64_t imm = | 2297 const int64_t imm = |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2565 __ cmpq(right, Immediate(0)); | 2578 __ cmpq(right, Immediate(0)); |
| 2566 __ j(LESS, &subtract, Assembler::kNearJump); | 2579 __ j(LESS, &subtract, Assembler::kNearJump); |
| 2567 __ addq(result, right); | 2580 __ addq(result, right); |
| 2568 __ jmp(&all_done, Assembler::kNearJump); | 2581 __ jmp(&all_done, Assembler::kNearJump); |
| 2569 __ Bind(&subtract); | 2582 __ Bind(&subtract); |
| 2570 __ subq(result, right); | 2583 __ subq(result, right); |
| 2571 __ Bind(&all_done); | 2584 __ Bind(&all_done); |
| 2572 __ SmiTag(result); | 2585 __ SmiTag(result); |
| 2573 break; | 2586 break; |
| 2574 } | 2587 } |
| 2588 case Token::kTRUNCDIVMOD: { | |
|
Florian Schneider
2013/11/14 10:17:44
I'm not sure how much making this operation a Bina
srdjan
2013/11/20 21:41:47
Created new instructions as suggested.
| |
| 2589 Label not_32bit, done; | |
| 2590 Register temp = locs()->temp(0).reg(); | |
| 2591 ASSERT(left == RAX); | |
| 2592 ASSERT((right != RDX) && (right != RAX)); | |
| 2593 ASSERT(temp == RDX); | |
| 2594 ASSERT((result != RDX) && (result != RAX)); | |
| 2595 // Handle divide by zero in runtime. | |
| 2596 __ testq(right, right); | |
| 2597 __ j(ZERO, deopt); | |
| 2598 // Check if both operands fit into 32bits as idiv with 64bit operands | |
| 2599 // requires twice as many cycles and has much higher latency. | |
| 2600 // We are checking this before untagging them to avoid corner case | |
| 2601 // dividing INT_MAX by -1 that raises exception because quotient is | |
| 2602 // too large for 32bit register. | |
| 2603 __ movsxd(temp, left); | |
| 2604 __ cmpq(temp, left); | |
| 2605 __ j(NOT_EQUAL, ¬_32bit); | |
| 2606 __ movsxd(temp, right); | |
| 2607 __ cmpq(temp, right); | |
| 2608 __ j(NOT_EQUAL, ¬_32bit); | |
| 2609 | |
| 2610 // Both operands are 31bit smis. Divide using 32bit idiv. | |
| 2611 __ SmiUntag(left); | |
| 2612 __ SmiUntag(right); | |
| 2613 __ cdq(); | |
| 2614 __ idivl(right); | |
| 2615 __ movsxd(RAX, RAX); | |
| 2616 __ movsxd(RDX, RDX); | |
| 2617 __ jmp(&done); | |
| 2618 | |
| 2619 // Divide using 64bit idiv. | |
| 2620 __ Bind(¬_32bit); | |
| 2621 __ SmiUntag(left); | |
| 2622 __ SmiUntag(right); | |
| 2623 __ cqo(); // Sign extend RAX -> RDX:RAX. | |
| 2624 __ idivq(right); // RAX: quotient, RDX: remainder. | |
| 2625 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2626 // case we cannot tag the result. | |
| 2627 __ CompareImmediate(RAX, Immediate(0x4000000000000000), PP); | |
| 2628 __ j(EQUAL, deopt); | |
| 2629 __ Bind(&done); | |
| 2630 | |
| 2631 // Modulo correction (RDX). | |
| 2632 // res = left % right; | |
| 2633 // if (res < 0) { | |
| 2634 // if (right < 0) { | |
| 2635 // res = res - right; | |
| 2636 // } else { | |
| 2637 // res = res + right; | |
| 2638 // } | |
| 2639 // } | |
| 2640 Label subtract, all_done; | |
| 2641 __ cmpq(RDX, Immediate(0)); | |
| 2642 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | |
| 2643 // Result is negative, adjust it. | |
| 2644 __ cmpq(right, Immediate(0)); | |
| 2645 __ j(LESS, &subtract, Assembler::kNearJump); | |
| 2646 __ addq(RDX, right); | |
| 2647 __ jmp(&all_done, Assembler::kNearJump); | |
| 2648 __ Bind(&subtract); | |
| 2649 __ subq(RDX, right); | |
| 2650 __ Bind(&all_done); | |
| 2651 __ SmiTag(result); | |
| 2652 | |
| 2653 __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); | |
| 2654 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); | |
| 2655 Address trunc_div_address( | |
| 2656 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, | |
| 2657 index_scale, | |
| 2658 result, | |
| 2659 0)); | |
| 2660 Address mod_address( | |
| 2661 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, | |
| 2662 index_scale, | |
| 2663 result, | |
| 2664 1)); | |
| 2665 __ SmiTag(RAX); | |
| 2666 __ SmiTag(RDX); | |
| 2667 __ StoreIntoObjectNoBarrier(result, trunc_div_address, RAX); | |
| 2668 __ StoreIntoObjectNoBarrier(result, mod_address, RDX); | |
| 2669 break; | |
| 2670 } | |
| 2575 case Token::kSHR: { | 2671 case Token::kSHR: { |
| 2576 if (CanDeoptimize()) { | 2672 if (CanDeoptimize()) { |
| 2577 __ CompareImmediate(right, Immediate(0), PP); | 2673 __ CompareImmediate(right, Immediate(0), PP); |
| 2578 __ j(LESS, deopt); | 2674 __ j(LESS, deopt); |
| 2579 } | 2675 } |
| 2580 __ SmiUntag(right); | 2676 __ SmiUntag(right); |
| 2581 // sarq operation masks the count to 6 bits. | 2677 // sarq operation masks the count to 6 bits. |
| 2582 const intptr_t kCountLimit = 0x3F; | 2678 const intptr_t kCountLimit = 0x3F; |
| 2583 Range* right_range = this->right()->definition()->range(); | 2679 Range* right_range = this->right()->definition()->range(); |
| 2584 if ((right_range == NULL) || | 2680 if ((right_range == NULL) || |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 2606 // Flow graph builder has dissected this operation to guarantee correct | 2702 // Flow graph builder has dissected this operation to guarantee correct |
| 2607 // behavior (short-circuit evaluation). | 2703 // behavior (short-circuit evaluation). |
| 2608 UNREACHABLE(); | 2704 UNREACHABLE(); |
| 2609 break; | 2705 break; |
| 2610 } | 2706 } |
| 2611 default: | 2707 default: |
| 2612 UNREACHABLE(); | 2708 UNREACHABLE(); |
| 2613 break; | 2709 break; |
| 2614 } | 2710 } |
| 2615 if (FLAG_throw_on_javascript_int_overflow) { | 2711 if (FLAG_throw_on_javascript_int_overflow) { |
| 2616 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 2712 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
|
Florian Schneider
2013/11/14 10:17:44
DIVMOD won't work with --throw_on_javascript_int_o
srdjan
2013/11/20 21:41:47
Good point, fixing it.
| |
| 2617 } | 2713 } |
| 2618 } | 2714 } |
| 2619 | 2715 |
| 2620 | 2716 |
| 2621 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { | 2717 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { |
| 2622 intptr_t left_cid = left()->Type()->ToCid(); | 2718 intptr_t left_cid = left()->Type()->ToCid(); |
| 2623 intptr_t right_cid = right()->Type()->ToCid(); | 2719 intptr_t right_cid = right()->Type()->ToCid(); |
| 2624 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 2720 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
| 2625 const intptr_t kNumInputs = 2; | 2721 const intptr_t kNumInputs = 2; |
| 2626 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); | 2722 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); |
| (...skipping 1990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4617 PcDescriptors::kOther, | 4713 PcDescriptors::kOther, |
| 4618 locs()); | 4714 locs()); |
| 4619 __ Drop(2); // Discard type arguments and receiver. | 4715 __ Drop(2); // Discard type arguments and receiver. |
| 4620 } | 4716 } |
| 4621 | 4717 |
| 4622 } // namespace dart | 4718 } // namespace dart |
| 4623 | 4719 |
| 4624 #undef __ | 4720 #undef __ |
| 4625 | 4721 |
| 4626 #endif // defined TARGET_ARCH_X64 | 4722 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |