| 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 2358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2369 break; | 2369 break; |
| 2370 } | 2370 } |
| 2371 if (FLAG_throw_on_javascript_int_overflow) { | 2371 if (FLAG_throw_on_javascript_int_overflow) { |
| 2372 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 2372 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2373 } | 2373 } |
| 2374 return; | 2374 return; |
| 2375 } // locs()->in(1).IsStackSlot(). | 2375 } // locs()->in(1).IsStackSlot(). |
| 2376 | 2376 |
| 2377 // if locs()->in(1).IsRegister. | 2377 // if locs()->in(1).IsRegister. |
| 2378 Register right = locs()->in(1).reg(); | 2378 Register right = locs()->in(1).reg(); |
| 2379 Range* right_range = this->right()->definition()->range(); |
| 2379 switch (op_kind()) { | 2380 switch (op_kind()) { |
| 2380 case Token::kADD: { | 2381 case Token::kADD: { |
| 2381 __ addq(left, right); | 2382 __ addq(left, right); |
| 2382 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2383 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2383 break; | 2384 break; |
| 2384 } | 2385 } |
| 2385 case Token::kSUB: { | 2386 case Token::kSUB: { |
| 2386 __ subq(left, right); | 2387 __ subq(left, right); |
| 2387 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2388 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2388 break; | 2389 break; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2409 break; | 2410 break; |
| 2410 } | 2411 } |
| 2411 case Token::kTRUNCDIV: { | 2412 case Token::kTRUNCDIV: { |
| 2412 Label not_32bit, done; | 2413 Label not_32bit, done; |
| 2413 | 2414 |
| 2414 Register temp = locs()->temp(0).reg(); | 2415 Register temp = locs()->temp(0).reg(); |
| 2415 ASSERT(left == RAX); | 2416 ASSERT(left == RAX); |
| 2416 ASSERT((right != RDX) && (right != RAX)); | 2417 ASSERT((right != RDX) && (right != RAX)); |
| 2417 ASSERT(temp == RDX); | 2418 ASSERT(temp == RDX); |
| 2418 ASSERT(result == RAX); | 2419 ASSERT(result == RAX); |
| 2419 | 2420 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 2420 // Handle divide by zero in runtime. | 2421 // Handle divide by zero in runtime. |
| 2421 __ testq(right, right); | 2422 __ testq(right, right); |
| 2422 __ j(ZERO, deopt); | 2423 __ j(ZERO, deopt); |
| 2423 | 2424 } |
| 2424 // Check if both operands fit into 32bits as idiv with 64bit operands | 2425 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 2425 // requires twice as many cycles and has much higher latency. | 2426 // requires twice as many cycles and has much higher latency. |
| 2426 // We are checking this before untagging them to avoid corner case | 2427 // We are checking this before untagging them to avoid corner case |
| 2427 // dividing INT_MAX by -1 that raises exception because quotient is | 2428 // dividing INT_MAX by -1 that raises exception because quotient is |
| 2428 // too large for 32bit register. | 2429 // too large for 32bit register. |
| 2429 __ movsxd(temp, left); | 2430 __ movsxd(temp, left); |
| 2430 __ cmpq(temp, left); | 2431 __ cmpq(temp, left); |
| 2431 __ j(NOT_EQUAL, ¬_32bit); | 2432 __ j(NOT_EQUAL, ¬_32bit); |
| 2432 __ movsxd(temp, right); | 2433 __ movsxd(temp, right); |
| 2433 __ cmpq(temp, right); | 2434 __ cmpq(temp, right); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2456 break; | 2457 break; |
| 2457 } | 2458 } |
| 2458 case Token::kMOD: { | 2459 case Token::kMOD: { |
| 2459 Label not_32bit, div_done; | 2460 Label not_32bit, div_done; |
| 2460 | 2461 |
| 2461 Register temp = locs()->temp(0).reg(); | 2462 Register temp = locs()->temp(0).reg(); |
| 2462 ASSERT(left == RDX); | 2463 ASSERT(left == RDX); |
| 2463 ASSERT((right != RDX) && (right != RAX)); | 2464 ASSERT((right != RDX) && (right != RAX)); |
| 2464 ASSERT(temp == RAX); | 2465 ASSERT(temp == RAX); |
| 2465 ASSERT(result == RDX); | 2466 ASSERT(result == RDX); |
| 2466 // Handle divide by zero in runtime. | 2467 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 2467 __ testq(right, right); | 2468 // Handle divide by zero in runtime. |
| 2468 __ j(ZERO, deopt); | 2469 __ testq(right, right); |
| 2470 __ j(ZERO, deopt); |
| 2471 } |
| 2469 // Check if both operands fit into 32bits as idiv with 64bit operands | 2472 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 2470 // requires twice as many cycles and has much higher latency. | 2473 // requires twice as many cycles and has much higher latency. |
| 2471 // We are checking this before untagging them to avoid corner case | 2474 // We are checking this before untagging them to avoid corner case |
| 2472 // dividing INT_MAX by -1 that raises exception because quotient is | 2475 // dividing INT_MAX by -1 that raises exception because quotient is |
| 2473 // too large for 32bit register. | 2476 // too large for 32bit register. |
| 2474 __ movsxd(temp, left); | 2477 __ movsxd(temp, left); |
| 2475 __ cmpq(temp, left); | 2478 __ cmpq(temp, left); |
| 2476 __ j(NOT_EQUAL, ¬_32bit); | 2479 __ j(NOT_EQUAL, ¬_32bit); |
| 2477 __ movsxd(temp, right); | 2480 __ movsxd(temp, right); |
| 2478 __ cmpq(temp, right); | 2481 __ cmpq(temp, right); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2495 __ idivq(right); // RAX: quotient, RDX: remainder. | 2498 __ idivq(right); // RAX: quotient, RDX: remainder. |
| 2496 __ Bind(&div_done); | 2499 __ Bind(&div_done); |
| 2497 // res = left % right; | 2500 // res = left % right; |
| 2498 // if (res < 0) { | 2501 // if (res < 0) { |
| 2499 // if (right < 0) { | 2502 // if (right < 0) { |
| 2500 // res = res - right; | 2503 // res = res - right; |
| 2501 // } else { | 2504 // } else { |
| 2502 // res = res + right; | 2505 // res = res + right; |
| 2503 // } | 2506 // } |
| 2504 // } | 2507 // } |
| 2505 Label subtract, all_done; | 2508 Label all_done; |
| 2506 __ cmpq(result, Immediate(0)); | 2509 __ cmpq(result, Immediate(0)); |
| 2507 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | 2510 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| 2508 // Result is negative, adjust it. | 2511 // Result is negative, adjust it. |
| 2509 __ cmpq(right, Immediate(0)); | 2512 if ((right_range == NULL) || right_range->Overlaps(-1, 1)) { |
| 2510 __ j(LESS, &subtract, Assembler::kNearJump); | 2513 Label subtract; |
| 2511 __ addq(result, right); | 2514 __ cmpq(right, Immediate(0)); |
| 2512 __ jmp(&all_done, Assembler::kNearJump); | 2515 __ j(LESS, &subtract, Assembler::kNearJump); |
| 2513 __ Bind(&subtract); | 2516 __ addq(result, right); |
| 2514 __ subq(result, right); | 2517 __ jmp(&all_done, Assembler::kNearJump); |
| 2518 __ Bind(&subtract); |
| 2519 __ subq(result, right); |
| 2520 } else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) { |
| 2521 // Right is positive. |
| 2522 __ addq(result, right); |
| 2523 } else { |
| 2524 // Right is negative. |
| 2525 __ subq(result, right); |
| 2526 } |
| 2515 __ Bind(&all_done); | 2527 __ Bind(&all_done); |
| 2516 __ SmiTag(result); | 2528 __ SmiTag(result); |
| 2517 break; | 2529 break; |
| 2518 } | 2530 } |
| 2519 case Token::kSHR: { | 2531 case Token::kSHR: { |
| 2520 if (CanDeoptimize()) { | 2532 if (CanDeoptimize()) { |
| 2521 __ CompareImmediate(right, Immediate(0), PP); | 2533 __ CompareImmediate(right, Immediate(0), PP); |
| 2522 __ j(LESS, deopt); | 2534 __ j(LESS, deopt); |
| 2523 } | 2535 } |
| 2524 __ SmiUntag(right); | 2536 __ SmiUntag(right); |
| 2525 // sarq operation masks the count to 6 bits. | 2537 // sarq operation masks the count to 6 bits. |
| 2526 const intptr_t kCountLimit = 0x3F; | 2538 const intptr_t kCountLimit = 0x3F; |
| 2527 Range* right_range = this->right()->definition()->range(); | |
| 2528 if ((right_range == NULL) || | 2539 if ((right_range == NULL) || |
| 2529 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { | 2540 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2530 __ CompareImmediate(right, Immediate(kCountLimit), PP); | 2541 __ CompareImmediate(right, Immediate(kCountLimit), PP); |
| 2531 Label count_ok; | 2542 Label count_ok; |
| 2532 __ j(LESS, &count_ok, Assembler::kNearJump); | 2543 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2533 __ LoadImmediate(right, Immediate(kCountLimit), PP); | 2544 __ LoadImmediate(right, Immediate(kCountLimit), PP); |
| 2534 __ Bind(&count_ok); | 2545 __ Bind(&count_ok); |
| 2535 } | 2546 } |
| 2536 ASSERT(right == RCX); // Count must be in RCX | 2547 ASSERT(right == RCX); // Count must be in RCX |
| 2537 __ SmiUntag(left); | 2548 __ SmiUntag(left); |
| (...skipping 1516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4054 if (kind() == MergedMathInstr::kTruncDivMod) { | 4065 if (kind() == MergedMathInstr::kTruncDivMod) { |
| 4055 Register left = locs()->in(0).reg(); | 4066 Register left = locs()->in(0).reg(); |
| 4056 Register right = locs()->in(1).reg(); | 4067 Register right = locs()->in(1).reg(); |
| 4057 Register result = locs()->out().reg(); | 4068 Register result = locs()->out().reg(); |
| 4058 Label not_32bit, done; | 4069 Label not_32bit, done; |
| 4059 Register temp = locs()->temp(0).reg(); | 4070 Register temp = locs()->temp(0).reg(); |
| 4060 ASSERT(left == RAX); | 4071 ASSERT(left == RAX); |
| 4061 ASSERT((right != RDX) && (right != RAX)); | 4072 ASSERT((right != RDX) && (right != RAX)); |
| 4062 ASSERT(temp == RDX); | 4073 ASSERT(temp == RDX); |
| 4063 ASSERT((result != RDX) && (result != RAX)); | 4074 ASSERT((result != RDX) && (result != RAX)); |
| 4064 // Handle divide by zero in runtime. | 4075 |
| 4065 __ testq(right, right); | 4076 Range* right_range = InputAt(1)->definition()->range(); |
| 4066 __ j(ZERO, deopt); | 4077 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 4078 // Handle divide by zero in runtime. |
| 4079 __ testq(right, right); |
| 4080 __ j(ZERO, deopt); |
| 4081 } |
| 4067 // Check if both operands fit into 32bits as idiv with 64bit operands | 4082 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 4068 // requires twice as many cycles and has much higher latency. | 4083 // requires twice as many cycles and has much higher latency. |
| 4069 // We are checking this before untagging them to avoid corner case | 4084 // We are checking this before untagging them to avoid corner case |
| 4070 // dividing INT_MAX by -1 that raises exception because quotient is | 4085 // dividing INT_MAX by -1 that raises exception because quotient is |
| 4071 // too large for 32bit register. | 4086 // too large for 32bit register. |
| 4072 __ movsxd(temp, left); | 4087 __ movsxd(temp, left); |
| 4073 __ cmpq(temp, left); | 4088 __ cmpq(temp, left); |
| 4074 __ j(NOT_EQUAL, ¬_32bit); | 4089 __ j(NOT_EQUAL, ¬_32bit); |
| 4075 __ movsxd(temp, right); | 4090 __ movsxd(temp, right); |
| 4076 __ cmpq(temp, right); | 4091 __ cmpq(temp, right); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4099 | 4114 |
| 4100 // Modulo correction (RDX). | 4115 // Modulo correction (RDX). |
| 4101 // res = left % right; | 4116 // res = left % right; |
| 4102 // if (res < 0) { | 4117 // if (res < 0) { |
| 4103 // if (right < 0) { | 4118 // if (right < 0) { |
| 4104 // res = res - right; | 4119 // res = res - right; |
| 4105 // } else { | 4120 // } else { |
| 4106 // res = res + right; | 4121 // res = res + right; |
| 4107 // } | 4122 // } |
| 4108 // } | 4123 // } |
| 4109 Label subtract, all_done; | 4124 Label all_done; |
| 4110 __ cmpq(RDX, Immediate(0)); | 4125 __ cmpq(RDX, Immediate(0)); |
| 4111 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | 4126 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| 4112 // Result is negative, adjust it. | 4127 // Result is negative, adjust it. |
| 4113 __ cmpq(right, Immediate(0)); | 4128 if ((right_range == NULL) || right_range->Overlaps(-1, 1)) { |
| 4114 __ j(LESS, &subtract, Assembler::kNearJump); | 4129 Label subtract; |
| 4115 __ addq(RDX, right); | 4130 __ cmpq(right, Immediate(0)); |
| 4116 __ jmp(&all_done, Assembler::kNearJump); | 4131 __ j(LESS, &subtract, Assembler::kNearJump); |
| 4117 __ Bind(&subtract); | 4132 __ addq(RDX, right); |
| 4118 __ subq(RDX, right); | 4133 __ jmp(&all_done, Assembler::kNearJump); |
| 4134 __ Bind(&subtract); |
| 4135 __ subq(RDX, right); |
| 4136 } else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) { |
| 4137 // Right is positive. |
| 4138 __ addq(RDX, right); |
| 4139 } else { |
| 4140 // Right is negative. |
| 4141 __ subq(RDX, right); |
| 4142 } |
| 4119 __ Bind(&all_done); | 4143 __ Bind(&all_done); |
| 4120 __ SmiTag(result); | 4144 __ SmiTag(result); |
| 4121 | 4145 |
| 4122 __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); | 4146 __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); |
| 4123 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); | 4147 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); |
| 4124 Address trunc_div_address( | 4148 Address trunc_div_address( |
| 4125 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, | 4149 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, |
| 4126 index_scale, | 4150 index_scale, |
| 4127 result, | 4151 result, |
| 4128 0)); | 4152 0)); |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4669 PcDescriptors::kOther, | 4693 PcDescriptors::kOther, |
| 4670 locs()); | 4694 locs()); |
| 4671 __ Drop(2); // Discard type arguments and receiver. | 4695 __ Drop(2); // Discard type arguments and receiver. |
| 4672 } | 4696 } |
| 4673 | 4697 |
| 4674 } // namespace dart | 4698 } // namespace dart |
| 4675 | 4699 |
| 4676 #undef __ | 4700 #undef __ |
| 4677 | 4701 |
| 4678 #endif // defined TARGET_ARCH_X64 | 4702 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |