| 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 2373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2384 break; | 2384 break; |
| 2385 } | 2385 } |
| 2386 if (FLAG_throw_on_javascript_int_overflow) { | 2386 if (FLAG_throw_on_javascript_int_overflow) { |
| 2387 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 2387 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2388 } | 2388 } |
| 2389 return; | 2389 return; |
| 2390 } // locs()->in(1).IsStackSlot(). | 2390 } // locs()->in(1).IsStackSlot(). |
| 2391 | 2391 |
| 2392 // if locs()->in(1).IsRegister. | 2392 // if locs()->in(1).IsRegister. |
| 2393 Register right = locs()->in(1).reg(); | 2393 Register right = locs()->in(1).reg(); |
| 2394 Range* right_range = this->right()->definition()->range(); |
| 2394 switch (op_kind()) { | 2395 switch (op_kind()) { |
| 2395 case Token::kADD: { | 2396 case Token::kADD: { |
| 2396 __ addq(left, right); | 2397 __ addq(left, right); |
| 2397 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2398 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2398 break; | 2399 break; |
| 2399 } | 2400 } |
| 2400 case Token::kSUB: { | 2401 case Token::kSUB: { |
| 2401 __ subq(left, right); | 2402 __ subq(left, right); |
| 2402 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2403 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2403 break; | 2404 break; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2424 break; | 2425 break; |
| 2425 } | 2426 } |
| 2426 case Token::kTRUNCDIV: { | 2427 case Token::kTRUNCDIV: { |
| 2427 Label not_32bit, done; | 2428 Label not_32bit, done; |
| 2428 | 2429 |
| 2429 Register temp = locs()->temp(0).reg(); | 2430 Register temp = locs()->temp(0).reg(); |
| 2430 ASSERT(left == RAX); | 2431 ASSERT(left == RAX); |
| 2431 ASSERT((right != RDX) && (right != RAX)); | 2432 ASSERT((right != RDX) && (right != RAX)); |
| 2432 ASSERT(temp == RDX); | 2433 ASSERT(temp == RDX); |
| 2433 ASSERT(result == RAX); | 2434 ASSERT(result == RAX); |
| 2434 | 2435 if ((right_range == NULL) || right_range->IsWithin(0, 0)) { |
| 2435 // Handle divide by zero in runtime. | 2436 // Handle divide by zero in runtime. |
| 2436 __ testq(right, right); | 2437 __ testq(right, right); |
| 2437 __ j(ZERO, deopt); | 2438 __ j(ZERO, deopt); |
| 2438 | 2439 } |
| 2439 // Check if both operands fit into 32bits as idiv with 64bit operands | 2440 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 2440 // requires twice as many cycles and has much higher latency. | 2441 // requires twice as many cycles and has much higher latency. |
| 2441 // We are checking this before untagging them to avoid corner case | 2442 // We are checking this before untagging them to avoid corner case |
| 2442 // dividing INT_MAX by -1 that raises exception because quotient is | 2443 // dividing INT_MAX by -1 that raises exception because quotient is |
| 2443 // too large for 32bit register. | 2444 // too large for 32bit register. |
| 2444 __ movsxd(temp, left); | 2445 __ movsxd(temp, left); |
| 2445 __ cmpq(temp, left); | 2446 __ cmpq(temp, left); |
| 2446 __ j(NOT_EQUAL, ¬_32bit); | 2447 __ j(NOT_EQUAL, ¬_32bit); |
| 2447 __ movsxd(temp, right); | 2448 __ movsxd(temp, right); |
| 2448 __ cmpq(temp, right); | 2449 __ cmpq(temp, right); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2471 break; | 2472 break; |
| 2472 } | 2473 } |
| 2473 case Token::kMOD: { | 2474 case Token::kMOD: { |
| 2474 Label not_32bit, div_done; | 2475 Label not_32bit, div_done; |
| 2475 | 2476 |
| 2476 Register temp = locs()->temp(0).reg(); | 2477 Register temp = locs()->temp(0).reg(); |
| 2477 ASSERT(left == RDX); | 2478 ASSERT(left == RDX); |
| 2478 ASSERT((right != RDX) && (right != RAX)); | 2479 ASSERT((right != RDX) && (right != RAX)); |
| 2479 ASSERT(temp == RAX); | 2480 ASSERT(temp == RAX); |
| 2480 ASSERT(result == RDX); | 2481 ASSERT(result == RDX); |
| 2481 // Handle divide by zero in runtime. | 2482 if ((right_range == NULL) || right_range->IsWithin(0, 0)) { |
| 2482 __ testq(right, right); | 2483 // Handle divide by zero in runtime. |
| 2483 __ j(ZERO, deopt); | 2484 __ testq(right, right); |
| 2485 __ j(ZERO, deopt); |
| 2486 } |
| 2484 // Check if both operands fit into 32bits as idiv with 64bit operands | 2487 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 2485 // requires twice as many cycles and has much higher latency. | 2488 // requires twice as many cycles and has much higher latency. |
| 2486 // We are checking this before untagging them to avoid corner case | 2489 // We are checking this before untagging them to avoid corner case |
| 2487 // dividing INT_MAX by -1 that raises exception because quotient is | 2490 // dividing INT_MAX by -1 that raises exception because quotient is |
| 2488 // too large for 32bit register. | 2491 // too large for 32bit register. |
| 2489 __ movsxd(temp, left); | 2492 __ movsxd(temp, left); |
| 2490 __ cmpq(temp, left); | 2493 __ cmpq(temp, left); |
| 2491 __ j(NOT_EQUAL, ¬_32bit); | 2494 __ j(NOT_EQUAL, ¬_32bit); |
| 2492 __ movsxd(temp, right); | 2495 __ movsxd(temp, right); |
| 2493 __ cmpq(temp, right); | 2496 __ cmpq(temp, right); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2510 __ idivq(right); // RAX: quotient, RDX: remainder. | 2513 __ idivq(right); // RAX: quotient, RDX: remainder. |
| 2511 __ Bind(&div_done); | 2514 __ Bind(&div_done); |
| 2512 // res = left % right; | 2515 // res = left % right; |
| 2513 // if (res < 0) { | 2516 // if (res < 0) { |
| 2514 // if (right < 0) { | 2517 // if (right < 0) { |
| 2515 // res = res - right; | 2518 // res = res - right; |
| 2516 // } else { | 2519 // } else { |
| 2517 // res = res + right; | 2520 // res = res + right; |
| 2518 // } | 2521 // } |
| 2519 // } | 2522 // } |
| 2520 Label subtract, all_done; | 2523 Label all_done; |
| 2521 __ cmpq(result, Immediate(0)); | 2524 __ cmpq(result, Immediate(0)); |
| 2522 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | 2525 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| 2523 // Result is negative, adjust it. | 2526 // Result is negative, adjust it. |
| 2524 __ cmpq(right, Immediate(0)); | 2527 if ((right_range == NULL) || right_range->IsWithin(-1, 1)) { |
| 2525 __ j(LESS, &subtract, Assembler::kNearJump); | 2528 Label subtract; |
| 2526 __ addq(result, right); | 2529 __ cmpq(right, Immediate(0)); |
| 2527 __ jmp(&all_done, Assembler::kNearJump); | 2530 __ j(LESS, &subtract, Assembler::kNearJump); |
| 2528 __ Bind(&subtract); | 2531 __ addq(result, right); |
| 2529 __ subq(result, right); | 2532 __ jmp(&all_done, Assembler::kNearJump); |
| 2533 __ Bind(&subtract); |
| 2534 __ subq(result, right); |
| 2535 } else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) { |
| 2536 // Right is positive. |
| 2537 __ addq(result, right); |
| 2538 } else { |
| 2539 // Right is negative. |
| 2540 __ subq(result, right); |
| 2541 } |
| 2530 __ Bind(&all_done); | 2542 __ Bind(&all_done); |
| 2531 __ SmiTag(result); | 2543 __ SmiTag(result); |
| 2532 break; | 2544 break; |
| 2533 } | 2545 } |
| 2534 case Token::kSHR: { | 2546 case Token::kSHR: { |
| 2535 if (CanDeoptimize()) { | 2547 if (CanDeoptimize()) { |
| 2536 __ CompareImmediate(right, Immediate(0), PP); | 2548 __ CompareImmediate(right, Immediate(0), PP); |
| 2537 __ j(LESS, deopt); | 2549 __ j(LESS, deopt); |
| 2538 } | 2550 } |
| 2539 __ SmiUntag(right); | 2551 __ SmiUntag(right); |
| 2540 // sarq operation masks the count to 6 bits. | 2552 // sarq operation masks the count to 6 bits. |
| 2541 const intptr_t kCountLimit = 0x3F; | 2553 const intptr_t kCountLimit = 0x3F; |
| 2542 Range* right_range = this->right()->definition()->range(); | |
| 2543 if ((right_range == NULL) || | 2554 if ((right_range == NULL) || |
| 2544 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { | 2555 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2545 __ CompareImmediate(right, Immediate(kCountLimit), PP); | 2556 __ CompareImmediate(right, Immediate(kCountLimit), PP); |
| 2546 Label count_ok; | 2557 Label count_ok; |
| 2547 __ j(LESS, &count_ok, Assembler::kNearJump); | 2558 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2548 __ LoadImmediate(right, Immediate(kCountLimit), PP); | 2559 __ LoadImmediate(right, Immediate(kCountLimit), PP); |
| 2549 __ Bind(&count_ok); | 2560 __ Bind(&count_ok); |
| 2550 } | 2561 } |
| 2551 ASSERT(right == RCX); // Count must be in RCX | 2562 ASSERT(right == RCX); // Count must be in RCX |
| 2552 __ SmiUntag(left); | 2563 __ SmiUntag(left); |
| (...skipping 1516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4069 if (kind() == MergedMathInstr::kTruncDivMod) { | 4080 if (kind() == MergedMathInstr::kTruncDivMod) { |
| 4070 Register left = locs()->in(0).reg(); | 4081 Register left = locs()->in(0).reg(); |
| 4071 Register right = locs()->in(1).reg(); | 4082 Register right = locs()->in(1).reg(); |
| 4072 Register result = locs()->out().reg(); | 4083 Register result = locs()->out().reg(); |
| 4073 Label not_32bit, done; | 4084 Label not_32bit, done; |
| 4074 Register temp = locs()->temp(0).reg(); | 4085 Register temp = locs()->temp(0).reg(); |
| 4075 ASSERT(left == RAX); | 4086 ASSERT(left == RAX); |
| 4076 ASSERT((right != RDX) && (right != RAX)); | 4087 ASSERT((right != RDX) && (right != RAX)); |
| 4077 ASSERT(temp == RDX); | 4088 ASSERT(temp == RDX); |
| 4078 ASSERT((result != RDX) && (result != RAX)); | 4089 ASSERT((result != RDX) && (result != RAX)); |
| 4079 // Handle divide by zero in runtime. | 4090 |
| 4080 __ testq(right, right); | 4091 Range* right_range = InputAt(1)->definition()->range(); |
| 4081 __ j(ZERO, deopt); | 4092 if ((right_range == NULL) || right_range->IsWithin(0, 0)) { |
| 4093 // Handle divide by zero in runtime. |
| 4094 __ testq(right, right); |
| 4095 __ j(ZERO, deopt); |
| 4096 } |
| 4082 // Check if both operands fit into 32bits as idiv with 64bit operands | 4097 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 4083 // requires twice as many cycles and has much higher latency. | 4098 // requires twice as many cycles and has much higher latency. |
| 4084 // We are checking this before untagging them to avoid corner case | 4099 // We are checking this before untagging them to avoid corner case |
| 4085 // dividing INT_MAX by -1 that raises exception because quotient is | 4100 // dividing INT_MAX by -1 that raises exception because quotient is |
| 4086 // too large for 32bit register. | 4101 // too large for 32bit register. |
| 4087 __ movsxd(temp, left); | 4102 __ movsxd(temp, left); |
| 4088 __ cmpq(temp, left); | 4103 __ cmpq(temp, left); |
| 4089 __ j(NOT_EQUAL, ¬_32bit); | 4104 __ j(NOT_EQUAL, ¬_32bit); |
| 4090 __ movsxd(temp, right); | 4105 __ movsxd(temp, right); |
| 4091 __ cmpq(temp, right); | 4106 __ cmpq(temp, right); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4114 | 4129 |
| 4115 // Modulo correction (RDX). | 4130 // Modulo correction (RDX). |
| 4116 // res = left % right; | 4131 // res = left % right; |
| 4117 // if (res < 0) { | 4132 // if (res < 0) { |
| 4118 // if (right < 0) { | 4133 // if (right < 0) { |
| 4119 // res = res - right; | 4134 // res = res - right; |
| 4120 // } else { | 4135 // } else { |
| 4121 // res = res + right; | 4136 // res = res + right; |
| 4122 // } | 4137 // } |
| 4123 // } | 4138 // } |
| 4124 Label subtract, all_done; | 4139 Label all_done; |
| 4125 __ cmpq(RDX, Immediate(0)); | 4140 __ cmpq(RDX, Immediate(0)); |
| 4126 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | 4141 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| 4127 // Result is negative, adjust it. | 4142 // Result is negative, adjust it. |
| 4128 __ cmpq(right, Immediate(0)); | 4143 if ((right_range == NULL) || right_range->IsWithin(-1, 1)) { |
| 4129 __ j(LESS, &subtract, Assembler::kNearJump); | 4144 Label subtract; |
| 4130 __ addq(RDX, right); | 4145 __ cmpq(right, Immediate(0)); |
| 4131 __ jmp(&all_done, Assembler::kNearJump); | 4146 __ j(LESS, &subtract, Assembler::kNearJump); |
| 4132 __ Bind(&subtract); | 4147 __ addq(RDX, right); |
| 4133 __ subq(RDX, right); | 4148 __ jmp(&all_done, Assembler::kNearJump); |
| 4149 __ Bind(&subtract); |
| 4150 __ subq(RDX, right); |
| 4151 } else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) { |
| 4152 // Right is positive. |
| 4153 __ addq(RDX, right); |
| 4154 } else { |
| 4155 // Right is negative. |
| 4156 __ subq(RDX, right); |
| 4157 } |
| 4134 __ Bind(&all_done); | 4158 __ Bind(&all_done); |
| 4135 __ SmiTag(result); | 4159 __ SmiTag(result); |
| 4136 | 4160 |
| 4137 __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); | 4161 __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); |
| 4138 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); | 4162 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); |
| 4139 Address trunc_div_address( | 4163 Address trunc_div_address( |
| 4140 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, | 4164 FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, |
| 4141 index_scale, | 4165 index_scale, |
| 4142 result, | 4166 result, |
| 4143 0)); | 4167 0)); |
| (...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4689 PcDescriptors::kOther, | 4713 PcDescriptors::kOther, |
| 4690 locs()); | 4714 locs()); |
| 4691 __ Drop(2); // Discard type arguments and receiver. | 4715 __ Drop(2); // Discard type arguments and receiver. |
| 4692 } | 4716 } |
| 4693 | 4717 |
| 4694 } // namespace dart | 4718 } // namespace dart |
| 4695 | 4719 |
| 4696 #undef __ | 4720 #undef __ |
| 4697 | 4721 |
| 4698 #endif // defined TARGET_ARCH_X64 | 4722 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |