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_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/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 default: | 325 default: |
| 326 UNREACHABLE(); | 326 UNREACHABLE(); |
| 327 return VS; | 327 return VS; |
| 328 } | 328 } |
| 329 } | 329 } |
| 330 | 330 |
| 331 | 331 |
| 332 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { | 332 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { |
| 333 const intptr_t kNumInputs = 2; | 333 const intptr_t kNumInputs = 2; |
| 334 if (operation_cid() == kMintCid) { | 334 if (operation_cid() == kMintCid) { |
| 335 const intptr_t kNumTemps = 1; | 335 const intptr_t kNumTemps = 3; |
| 336 LocationSummary* locs = | 336 LocationSummary* locs = |
| 337 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 337 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 338 locs->set_in(0, Location::RequiresFpuRegister()); | 338 locs->set_in(0, Location::RequiresFpuRegister()); |
| 339 locs->set_in(1, Location::RequiresFpuRegister()); | 339 locs->set_in(1, Location::RequiresFpuRegister()); |
| 340 locs->set_temp(0, Location::RequiresRegister()); | 340 locs->set_temp(0, Location::RequiresFpuRegister()); |
| 341 locs->set_temp(1, Location::RequiresRegister()); | |
| 342 locs->set_temp(2, Location::RequiresRegister()); | |
| 341 locs->set_out(Location::RequiresRegister()); | 343 locs->set_out(Location::RequiresRegister()); |
| 342 return locs; | 344 return locs; |
| 343 } | 345 } |
| 344 if (operation_cid() == kDoubleCid) { | 346 if (operation_cid() == kDoubleCid) { |
| 345 const intptr_t kNumTemps = 0; | 347 const intptr_t kNumTemps = 0; |
| 346 LocationSummary* locs = | 348 LocationSummary* locs = |
| 347 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 349 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 348 locs->set_in(0, Location::RequiresFpuRegister()); | 350 locs->set_in(0, Location::RequiresFpuRegister()); |
| 349 locs->set_in(1, Location::RequiresFpuRegister()); | 351 locs->set_in(1, Location::RequiresFpuRegister()); |
| 350 locs->set_out(Location::RequiresRegister()); | 352 locs->set_out(Location::RequiresRegister()); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 true_condition = FlipCondition(true_condition); | 441 true_condition = FlipCondition(true_condition); |
| 440 } else if (right.IsConstant()) { | 442 } else if (right.IsConstant()) { |
| 441 __ CompareObject(left.reg(), right.constant()); | 443 __ CompareObject(left.reg(), right.constant()); |
| 442 } else { | 444 } else { |
| 443 __ cmp(left.reg(), ShifterOperand(right.reg())); | 445 __ cmp(left.reg(), ShifterOperand(right.reg())); |
| 444 } | 446 } |
| 445 return true_condition; | 447 return true_condition; |
| 446 } | 448 } |
| 447 | 449 |
| 448 | 450 |
| 451 static Condition TokenKindToMintCondition(Token::Kind kind) { | |
| 452 switch (kind) { | |
| 453 case Token::kEQ: return EQ; | |
| 454 case Token::kNE: return NE; | |
| 455 case Token::kLT: return LT; | |
| 456 case Token::kGT: return GT; | |
| 457 case Token::kLTE: return LE; | |
| 458 case Token::kGTE: return GE; | |
| 459 default: | |
| 460 UNREACHABLE(); | |
| 461 return VS; | |
| 462 } | |
| 463 } | |
| 464 | |
| 465 | |
| 466 static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | |
| 467 LocationSummary* locs, | |
| 468 Token::Kind kind) { | |
| 469 ASSERT(Token::IsEqualityOperator(kind)); | |
| 470 QRegister left = locs->in(0).fpu_reg(); | |
| 471 QRegister right = locs->in(1).fpu_reg(); | |
| 472 QRegister tmpq = locs->temp(0).fpu_reg(); | |
| 473 Register tmp_lo = locs->temp(1).reg(); | |
| 474 Register tmp_hi = locs->temp(2).reg(); | |
| 475 | |
| 476 __ vceqqi(kWord, tmpq, left, right); | |
| 477 __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(tmpq)); | |
| 478 // tmp_lo and tmp_hi must both be 0xffffffff. | |
| 479 __ and_(tmp_lo, tmp_lo, ShifterOperand(tmp_hi)); | |
| 480 | |
| 481 Condition true_condition = TokenKindToMintCondition(kind); | |
| 482 __ CompareImmediate(tmp_lo, 0xffffffff); | |
| 483 return true_condition; | |
| 484 } | |
| 485 | |
| 486 | |
| 487 static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, | |
| 488 LocationSummary* locs, | |
| 489 Token::Kind kind) { | |
| 490 QRegister left = locs->in(0).fpu_reg(); | |
| 491 QRegister right = locs->in(1).fpu_reg(); | |
| 492 DRegister dleft0 = EvenDRegisterOf(left); | |
| 493 DRegister dright0 = EvenDRegisterOf(right); | |
| 494 SRegister sleft0 = EvenSRegisterOf(dleft0); | |
| 495 SRegister sleft1 = OddSRegisterOf(dleft0); | |
| 496 SRegister sright0 = EvenSRegisterOf(dright0); | |
| 497 SRegister sright1 = OddSRegisterOf(dright0); | |
| 498 | |
| 499 Register tmp_left = locs->temp(0).reg(); | |
| 500 Register tmp_right = locs->temp(1).reg(); | |
| 501 | |
| 502 // 64-bit comparison | |
| 503 Condition hi_true_cond, hi_false_cond, lo_false_cond; | |
| 504 switch (kind) { | |
| 505 case Token::kLT: | |
| 506 case Token::kLTE: | |
| 507 hi_true_cond = LT; | |
| 508 hi_false_cond = GT; | |
| 509 lo_false_cond = (kind == Token::kLT) ? CS : HI; | |
| 510 break; | |
| 511 case Token::kGT: | |
| 512 case Token::kGTE: | |
| 513 hi_true_cond = GT; | |
| 514 hi_false_cond = LT; | |
| 515 lo_false_cond = (kind == Token::kGT) ? LS : CC; | |
| 516 break; | |
| 517 default: | |
| 518 UNREACHABLE(); | |
| 519 hi_true_cond = hi_false_cond = lo_false_cond = VS; | |
| 520 } | |
| 521 | |
| 522 Label is_true, is_false, done; | |
| 523 __ vmovrs(tmp_left, sleft1); | |
| 524 __ vmovrs(tmp_right, sright1); | |
| 525 __ cmp(tmp_left, ShifterOperand(tmp_right)); | |
| 526 __ b(&is_false, hi_false_cond); | |
| 527 __ b(&is_true, hi_true_cond); | |
| 528 | |
| 529 __ vmovrs(tmp_left, sleft0); | |
| 530 __ vmovrs(tmp_right, sright0); | |
| 531 __ cmp(tmp_left, ShifterOperand(tmp_right)); | |
| 532 __ b(&is_false, lo_false_cond); | |
| 533 // Else is true. | |
| 534 __ b(&is_true); | |
| 535 | |
| 536 __ Bind(&is_false); | |
| 537 __ LoadImmediate(tmp_left, 0); | |
| 538 __ b(&done); | |
| 539 __ Bind(&is_true); | |
| 540 __ LoadImmediate(tmp_left, 1); | |
| 541 __ Bind(&done); | |
| 542 return NegateCondition(lo_false_cond); | |
| 543 } | |
| 544 | |
| 545 | |
| 449 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 546 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 450 switch (kind) { | 547 switch (kind) { |
| 451 case Token::kEQ: return EQ; | 548 case Token::kEQ: return EQ; |
| 452 case Token::kNE: return NE; | 549 case Token::kNE: return NE; |
| 453 case Token::kLT: return LT; | 550 case Token::kLT: return LT; |
| 454 case Token::kGT: return GT; | 551 case Token::kGT: return GT; |
| 455 case Token::kLTE: return LE; | 552 case Token::kLTE: return LE; |
| 456 case Token::kGTE: return GE; | 553 case Token::kGTE: return GE; |
| 457 default: | 554 default: |
| 458 UNREACHABLE(); | 555 UNREACHABLE(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 472 __ vmstat(); | 569 __ vmstat(); |
| 473 Condition true_condition = TokenKindToDoubleCondition(kind); | 570 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 474 return true_condition; | 571 return true_condition; |
| 475 } | 572 } |
| 476 | 573 |
| 477 | 574 |
| 478 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 575 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 479 BranchLabels labels) { | 576 BranchLabels labels) { |
| 480 if (operation_cid() == kSmiCid) { | 577 if (operation_cid() == kSmiCid) { |
| 481 return EmitSmiComparisonOp(compiler, locs(), kind()); | 578 return EmitSmiComparisonOp(compiler, locs(), kind()); |
| 579 } else if (operation_cid() == kMintCid) { | |
| 580 return EmitUnboxedMintEqualityOp(compiler, locs(), kind()); | |
| 482 } else { | 581 } else { |
| 483 ASSERT(operation_cid() == kDoubleCid); | 582 ASSERT(operation_cid() == kDoubleCid); |
| 484 return EmitDoubleComparisonOp(compiler, locs(), kind()); | 583 return EmitDoubleComparisonOp(compiler, locs(), kind()); |
| 485 } | 584 } |
| 486 } | 585 } |
| 487 | 586 |
| 488 | 587 |
| 489 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 588 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 490 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 589 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 491 | 590 |
| 492 // The ARM code does not use true- and false-labels here. | 591 // The ARM code does not use true- and false-labels here. |
| 493 BranchLabels labels = { NULL, NULL, NULL }; | 592 BranchLabels labels = { NULL, NULL, NULL }; |
| 494 Condition true_condition = EmitComparisonCode(compiler, labels); | 593 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 495 | 594 |
| 496 Register result = locs()->out().reg(); | 595 Register result = locs()->out().reg(); |
| 497 if (operation_cid() == kSmiCid) { | 596 if ((operation_cid() == kSmiCid) || (operation_cid() == kMintCid)) { |
| 498 __ LoadObject(result, Bool::True(), true_condition); | 597 __ LoadObject(result, Bool::True(), true_condition); |
| 499 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); | 598 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); |
| 500 } else { | 599 } else { |
| 501 ASSERT(operation_cid() == kDoubleCid); | 600 ASSERT(operation_cid() == kDoubleCid); |
| 502 Label done; | 601 Label done; |
| 503 __ LoadObject(result, Bool::False()); | 602 __ LoadObject(result, Bool::False()); |
| 504 if (true_condition != NE) { | 603 if (true_condition != NE) { |
| 505 __ b(&done, VS); // x == NaN -> false, x != NaN -> true. | 604 __ b(&done, VS); // x == NaN -> false, x != NaN -> true. |
| 506 } | 605 } |
| 507 __ LoadObject(result, Bool::True(), true_condition); | 606 __ LoadObject(result, Bool::True(), true_condition); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 602 : Location::RegisterOrConstant(right())); | 701 : Location::RegisterOrConstant(right())); |
| 603 summary->set_out(Location::RequiresRegister()); | 702 summary->set_out(Location::RequiresRegister()); |
| 604 return summary; | 703 return summary; |
| 605 } | 704 } |
| 606 | 705 |
| 607 | 706 |
| 608 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 707 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 609 BranchLabels labels) { | 708 BranchLabels labels) { |
| 610 if (operation_cid() == kSmiCid) { | 709 if (operation_cid() == kSmiCid) { |
| 611 return EmitSmiComparisonOp(compiler, locs(), kind()); | 710 return EmitSmiComparisonOp(compiler, locs(), kind()); |
| 711 } else if (operation_cid() == kMintCid) { | |
| 712 return EmitUnboxedMintComparisonOp(compiler, locs(), kind()); | |
| 612 } else { | 713 } else { |
| 613 ASSERT(operation_cid() == kDoubleCid); | 714 ASSERT(operation_cid() == kDoubleCid); |
| 614 return EmitDoubleComparisonOp(compiler, locs(), kind()); | 715 return EmitDoubleComparisonOp(compiler, locs(), kind()); |
| 615 } | 716 } |
| 616 } | 717 } |
| 617 | 718 |
| 618 | 719 |
| 619 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 720 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 620 // The ARM code does not use true- and false-labels here. | 721 // The ARM code does not use true- and false-labels here. |
| 621 BranchLabels labels = { NULL, NULL, NULL }; | 722 BranchLabels labels = { NULL, NULL, NULL }; |
| 622 Condition true_condition = EmitComparisonCode(compiler, labels); | 723 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 623 | 724 |
| 624 Register result = locs()->out().reg(); | 725 Register result = locs()->out().reg(); |
| 625 if (operation_cid() == kSmiCid) { | 726 if (operation_cid() == kSmiCid) { |
| 626 __ LoadObject(result, Bool::True(), true_condition); | 727 __ LoadObject(result, Bool::True(), true_condition); |
| 627 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); | 728 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); |
| 729 } else if (operation_cid() == kMintCid) { | |
| 730 Register cr = locs()->temp(0).reg(); | |
| 731 __ LoadObject(result, Bool::True()); | |
| 732 __ CompareImmediate(cr, 1); | |
| 733 __ LoadObject(result, Bool::False(), NE); | |
| 628 } else { | 734 } else { |
| 629 ASSERT(operation_cid() == kDoubleCid); | 735 ASSERT(operation_cid() == kDoubleCid); |
| 630 Label done; | 736 Label done; |
| 631 __ LoadObject(result, Bool::False()); | 737 __ LoadObject(result, Bool::False()); |
| 632 if (true_condition != NE) { | 738 if (true_condition != NE) { |
| 633 __ b(&done, VS); // x == NaN -> false, x != NaN -> true. | 739 __ b(&done, VS); // x == NaN -> false, x != NaN -> true. |
| 634 } | 740 } |
| 635 __ LoadObject(result, Bool::True(), true_condition); | 741 __ LoadObject(result, Bool::True(), true_condition); |
| 636 __ Bind(&done); | 742 __ Bind(&done); |
| 637 } | 743 } |
| 638 } | 744 } |
| 639 | 745 |
| 640 | 746 |
| 641 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 747 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 642 BranchInstr* branch) { | 748 BranchInstr* branch) { |
| 643 BranchLabels labels = compiler->CreateBranchLabels(branch); | 749 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 644 Condition true_condition = EmitComparisonCode(compiler, labels); | 750 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 645 | 751 |
| 646 if (operation_cid() == kDoubleCid) { | 752 if (operation_cid() == kSmiCid) { |
| 753 EmitBranchOnCondition(compiler, true_condition, labels); | |
| 754 } else if (operation_cid() == kMintCid) { | |
| 755 Register result = locs()->temp(0).reg(); | |
| 756 __ CompareImmediate(result, 1); | |
| 757 __ b(labels.true_label, EQ); | |
| 758 __ b(labels.false_label, NE); | |
| 759 } else if (operation_cid() == kDoubleCid) { | |
| 647 Label* nan_result = (true_condition == NE) ? | 760 Label* nan_result = (true_condition == NE) ? |
| 648 labels.true_label : labels.false_label; | 761 labels.true_label : labels.false_label; |
| 649 __ b(nan_result, VS); | 762 __ b(nan_result, VS); |
| 763 EmitBranchOnCondition(compiler, true_condition, labels); | |
| 650 } | 764 } |
| 651 EmitBranchOnCondition(compiler, true_condition, labels); | |
| 652 } | 765 } |
| 653 | 766 |
| 654 | 767 |
| 655 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const { | 768 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const { |
| 656 const intptr_t kNumInputs = 0; | 769 const intptr_t kNumInputs = 0; |
| 657 const intptr_t kNumTemps = 3; | 770 const intptr_t kNumTemps = 3; |
| 658 LocationSummary* locs = | 771 LocationSummary* locs = |
| 659 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 772 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 660 locs->set_temp(0, Location::RegisterLocation(R1)); | 773 locs->set_temp(0, Location::RegisterLocation(R1)); |
| 661 locs->set_temp(1, Location::RegisterLocation(R2)); | 774 locs->set_temp(1, Location::RegisterLocation(R2)); |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 964 element_address = Address(array, index.reg(), LSL, 0); | 1077 element_address = Address(array, index.reg(), LSL, 0); |
| 965 | 1078 |
| 966 if ((representation() == kUnboxedDouble) || | 1079 if ((representation() == kUnboxedDouble) || |
| 967 (representation() == kUnboxedMint) || | 1080 (representation() == kUnboxedMint) || |
| 968 (representation() == kUnboxedFloat32x4) || | 1081 (representation() == kUnboxedFloat32x4) || |
| 969 (representation() == kUnboxedInt32x4) || | 1082 (representation() == kUnboxedInt32x4) || |
| 970 (representation() == kUnboxedFloat64x2)) { | 1083 (representation() == kUnboxedFloat64x2)) { |
| 971 QRegister result = locs()->out().fpu_reg(); | 1084 QRegister result = locs()->out().fpu_reg(); |
| 972 DRegister dresult0 = EvenDRegisterOf(result); | 1085 DRegister dresult0 = EvenDRegisterOf(result); |
| 973 DRegister dresult1 = OddDRegisterOf(result); | 1086 DRegister dresult1 = OddDRegisterOf(result); |
| 1087 Register idx = index.reg(); | |
| 974 switch (class_id()) { | 1088 switch (class_id()) { |
| 975 case kTypedDataInt32ArrayCid: | 1089 case kTypedDataInt32ArrayCid: |
| 976 UNIMPLEMENTED(); | 1090 __ veorq(result, result, result); |
| 1091 __ ldr(TMP, element_address); | |
| 1092 // Re-use the index register so we don't have to require a low-numbered | |
| 1093 // Q register. | |
| 1094 __ eor(idx, idx, ShifterOperand(idx)); | |
|
regis
2014/03/20 20:39:35
Wouldn't __ LoadImmediate(idx, 0) be clearer?
zra
2014/03/20 23:49:25
Done.
| |
| 1095 __ cmp(TMP, ShifterOperand(0)); | |
| 1096 // Sign-extend if the element is < 0; | |
| 1097 __ LoadImmediate(idx, -1, LT); | |
|
regis
2014/03/20 20:39:35
Instead of the 3 instructions above (including a b
zra
2014/03/20 23:49:25
Done.
| |
| 1098 __ vmovdrr(dresult0, TMP, idx); | |
| 977 break; | 1099 break; |
| 978 case kTypedDataUint32ArrayCid: | 1100 case kTypedDataUint32ArrayCid: |
| 979 UNIMPLEMENTED(); | 1101 __ veorq(result, result, result); |
| 1102 __ ldr(TMP, element_address); | |
| 1103 // Re-use the index register so we don't have to require a low-numbered | |
| 1104 // Q register. | |
| 1105 __ eor(idx, idx, ShifterOperand(idx)); | |
|
regis
2014/03/20 20:39:35
Wouldn't __ LoadImmediate(idx, 0) be clearer?
zra
2014/03/20 23:49:25
Done.
| |
| 1106 __ vmovdrr(dresult0, TMP, idx); | |
| 980 break; | 1107 break; |
| 981 case kTypedDataFloat32ArrayCid: | 1108 case kTypedDataFloat32ArrayCid: |
| 982 // Load single precision float. | 1109 // Load single precision float. |
| 983 // vldrs does not support indexed addressing. | 1110 // vldrs does not support indexed addressing. |
| 984 __ add(index.reg(), index.reg(), ShifterOperand(array)); | 1111 __ add(index.reg(), index.reg(), ShifterOperand(array)); |
| 985 element_address = Address(index.reg(), 0); | 1112 element_address = Address(index.reg(), 0); |
| 986 __ vldrs(EvenSRegisterOf(dresult0), element_address); | 1113 __ vldrs(EvenSRegisterOf(dresult0), element_address); |
| 987 break; | 1114 break; |
| 988 case kTypedDataFloat64ArrayCid: | 1115 case kTypedDataFloat64ArrayCid: |
| 989 // vldrd does not support indexed addressing. | 1116 // vldrd does not support indexed addressing. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1034 // Verify that the signed value in 'result' can fit inside a Smi. | 1161 // Verify that the signed value in 'result' can fit inside a Smi. |
| 1035 __ CompareImmediate(result, 0xC0000000); | 1162 __ CompareImmediate(result, 0xC0000000); |
| 1036 __ b(deopt, MI); | 1163 __ b(deopt, MI); |
| 1037 __ SmiTag(result); | 1164 __ SmiTag(result); |
| 1038 } | 1165 } |
| 1039 break; | 1166 break; |
| 1040 case kTypedDataUint32ArrayCid: { | 1167 case kTypedDataUint32ArrayCid: { |
| 1041 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load); | 1168 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load); |
| 1042 __ ldr(result, element_address); | 1169 __ ldr(result, element_address); |
| 1043 // Verify that the unsigned value in 'result' can fit inside a Smi. | 1170 // Verify that the unsigned value in 'result' can fit inside a Smi. |
| 1044 __ tst(result, ShifterOperand(0xC0000000)); | 1171 __ TestImmediate(result, 0xC0000000); |
| 1045 __ b(deopt, NE); | 1172 __ b(deopt, NE); |
| 1046 __ SmiTag(result); | 1173 __ SmiTag(result); |
| 1047 } | 1174 } |
| 1048 break; | 1175 break; |
| 1049 default: | 1176 default: |
| 1050 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); | 1177 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); |
| 1051 __ ldr(result, element_address); | 1178 __ ldr(result, element_address); |
| 1052 break; | 1179 break; |
| 1053 } | 1180 } |
| 1054 } | 1181 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1107 : Location::RegisterOrConstant(value())); | 1234 : Location::RegisterOrConstant(value())); |
| 1108 break; | 1235 break; |
| 1109 case kExternalTypedDataUint8ArrayCid: | 1236 case kExternalTypedDataUint8ArrayCid: |
| 1110 case kExternalTypedDataUint8ClampedArrayCid: | 1237 case kExternalTypedDataUint8ClampedArrayCid: |
| 1111 case kTypedDataInt8ArrayCid: | 1238 case kTypedDataInt8ArrayCid: |
| 1112 case kTypedDataUint8ArrayCid: | 1239 case kTypedDataUint8ArrayCid: |
| 1113 case kTypedDataUint8ClampedArrayCid: | 1240 case kTypedDataUint8ClampedArrayCid: |
| 1114 case kOneByteStringCid: | 1241 case kOneByteStringCid: |
| 1115 case kTypedDataInt16ArrayCid: | 1242 case kTypedDataInt16ArrayCid: |
| 1116 case kTypedDataUint16ArrayCid: | 1243 case kTypedDataUint16ArrayCid: |
| 1244 locs->set_in(2, Location::WritableRegister()); | |
| 1245 break; | |
| 1117 case kTypedDataInt32ArrayCid: | 1246 case kTypedDataInt32ArrayCid: |
| 1118 case kTypedDataUint32ArrayCid: | 1247 case kTypedDataUint32ArrayCid: |
| 1119 locs->set_in(2, Location::WritableRegister()); | 1248 // Mints are stored in Q registers. For smis, use a writable register |
| 1249 // because the value must be untagged before storing. | |
| 1250 locs->set_in(2, value()->IsSmiValue() | |
| 1251 ? Location::WritableRegister() | |
| 1252 : Location::FpuRegisterLocation(Q7)); | |
| 1120 break; | 1253 break; |
| 1121 case kTypedDataFloat32ArrayCid: | 1254 case kTypedDataFloat32ArrayCid: |
| 1122 // Need low register (<= Q7). | 1255 // Need low register (<= Q7). |
| 1123 locs->set_in(2, Location::FpuRegisterLocation(Q7)); | 1256 locs->set_in(2, Location::FpuRegisterLocation(Q7)); |
| 1124 break; | 1257 break; |
| 1125 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. | 1258 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. |
| 1126 case kTypedDataInt32x4ArrayCid: | 1259 case kTypedDataInt32x4ArrayCid: |
| 1127 case kTypedDataFloat32x4ArrayCid: | 1260 case kTypedDataFloat32x4ArrayCid: |
| 1128 case kTypedDataFloat64x2ArrayCid: | 1261 case kTypedDataFloat64x2ArrayCid: |
| 1129 locs->set_in(2, Location::RequiresFpuRegister()); | 1262 locs->set_in(2, Location::RequiresFpuRegister()); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1239 break; | 1372 break; |
| 1240 } | 1373 } |
| 1241 case kTypedDataInt32ArrayCid: | 1374 case kTypedDataInt32ArrayCid: |
| 1242 case kTypedDataUint32ArrayCid: { | 1375 case kTypedDataUint32ArrayCid: { |
| 1243 if (value()->IsSmiValue()) { | 1376 if (value()->IsSmiValue()) { |
| 1244 ASSERT(RequiredInputRepresentation(2) == kTagged); | 1377 ASSERT(RequiredInputRepresentation(2) == kTagged); |
| 1245 Register value = locs()->in(2).reg(); | 1378 Register value = locs()->in(2).reg(); |
| 1246 __ SmiUntag(value); | 1379 __ SmiUntag(value); |
| 1247 __ str(value, element_address); | 1380 __ str(value, element_address); |
| 1248 } else { | 1381 } else { |
| 1249 UNIMPLEMENTED(); | 1382 ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); |
| 1383 QRegister value = locs()->in(2).fpu_reg(); | |
| 1384 ASSERT(value == Q7); | |
| 1385 __ vmovrs(TMP, EvenSRegisterOf(EvenDRegisterOf(value))); | |
| 1386 __ str(TMP, element_address); | |
| 1250 } | 1387 } |
| 1251 break; | 1388 break; |
| 1252 } | 1389 } |
| 1253 case kTypedDataFloat32ArrayCid: { | 1390 case kTypedDataFloat32ArrayCid: { |
| 1254 SRegister value = | 1391 SRegister value = |
| 1255 EvenSRegisterOf(EvenDRegisterOf(locs()->in(2).fpu_reg())); | 1392 EvenSRegisterOf(EvenDRegisterOf(locs()->in(2).fpu_reg())); |
| 1256 __ add(index.reg(), index.reg(), ShifterOperand(array)); | 1393 __ add(index.reg(), index.reg(), ShifterOperand(array)); |
| 1257 __ StoreSToOffset(value, index.reg(), 0); | 1394 __ StoreSToOffset(value, index.reg(), 0); |
| 1258 break; | 1395 break; |
| 1259 } | 1396 } |
| (...skipping 2450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3710 QRegister right = locs()->in(1).fpu_reg(); | 3847 QRegister right = locs()->in(1).fpu_reg(); |
| 3711 QRegister result = locs()->out().fpu_reg(); | 3848 QRegister result = locs()->out().fpu_reg(); |
| 3712 | 3849 |
| 3713 switch (op_kind()) { | 3850 switch (op_kind()) { |
| 3714 case MethodRecognizer::kFloat32x4Equal: | 3851 case MethodRecognizer::kFloat32x4Equal: |
| 3715 __ vceqqs(result, left, right); | 3852 __ vceqqs(result, left, right); |
| 3716 break; | 3853 break; |
| 3717 case MethodRecognizer::kFloat32x4NotEqual: | 3854 case MethodRecognizer::kFloat32x4NotEqual: |
| 3718 __ vceqqs(result, left, right); | 3855 __ vceqqs(result, left, right); |
| 3719 // Invert the result. | 3856 // Invert the result. |
| 3720 __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. | 3857 __ vmvnq(result, result); |
| 3721 __ vornq(result, QTMP, result); // result <- ~result. | |
| 3722 break; | 3858 break; |
| 3723 case MethodRecognizer::kFloat32x4GreaterThan: | 3859 case MethodRecognizer::kFloat32x4GreaterThan: |
| 3724 __ vcgtqs(result, left, right); | 3860 __ vcgtqs(result, left, right); |
| 3725 break; | 3861 break; |
| 3726 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | 3862 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: |
| 3727 __ vcgeqs(result, left, right); | 3863 __ vcgeqs(result, left, right); |
| 3728 break; | 3864 break; |
| 3729 case MethodRecognizer::kFloat32x4LessThan: | 3865 case MethodRecognizer::kFloat32x4LessThan: |
| 3730 __ vcgtqs(result, right, left); | 3866 __ vcgtqs(result, right, left); |
| 3731 break; | 3867 break; |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4360 void Int32x4SelectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4496 void Int32x4SelectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 4361 QRegister mask = locs()->in(0).fpu_reg(); | 4497 QRegister mask = locs()->in(0).fpu_reg(); |
| 4362 QRegister trueValue = locs()->in(1).fpu_reg(); | 4498 QRegister trueValue = locs()->in(1).fpu_reg(); |
| 4363 QRegister falseValue = locs()->in(2).fpu_reg(); | 4499 QRegister falseValue = locs()->in(2).fpu_reg(); |
| 4364 QRegister out = locs()->out().fpu_reg(); | 4500 QRegister out = locs()->out().fpu_reg(); |
| 4365 QRegister temp = locs()->temp(0).fpu_reg(); | 4501 QRegister temp = locs()->temp(0).fpu_reg(); |
| 4366 | 4502 |
| 4367 // Copy mask. | 4503 // Copy mask. |
| 4368 __ vmovq(temp, mask); | 4504 __ vmovq(temp, mask); |
| 4369 // Invert it. | 4505 // Invert it. |
| 4370 __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. | 4506 __ vmvnq(temp, temp); |
| 4371 __ vornq(temp, QTMP, temp); // temp <- ~temp. | |
| 4372 // mask = mask & trueValue. | 4507 // mask = mask & trueValue. |
| 4373 __ vandq(mask, mask, trueValue); | 4508 __ vandq(mask, mask, trueValue); |
| 4374 // temp = temp & falseValue. | 4509 // temp = temp & falseValue. |
| 4375 __ vandq(temp, temp, falseValue); | 4510 __ vandq(temp, temp, falseValue); |
| 4376 // out = mask | temp. | 4511 // out = mask | temp. |
| 4377 __ vorrq(out, mask, temp); | 4512 __ vorrq(out, mask, temp); |
| 4378 } | 4513 } |
| 4379 | 4514 |
| 4380 | 4515 |
| 4381 LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const { | 4516 LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const { |
| (...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5177 __ b(deopt, CS); | 5312 __ b(deopt, CS); |
| 5178 } else { | 5313 } else { |
| 5179 Register length = length_loc.reg(); | 5314 Register length = length_loc.reg(); |
| 5180 Register index = index_loc.reg(); | 5315 Register index = index_loc.reg(); |
| 5181 __ cmp(index, ShifterOperand(length)); | 5316 __ cmp(index, ShifterOperand(length)); |
| 5182 __ b(deopt, CS); | 5317 __ b(deopt, CS); |
| 5183 } | 5318 } |
| 5184 } | 5319 } |
| 5185 | 5320 |
| 5186 | 5321 |
| 5322 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, | |
| 5323 Label* overflow, | |
| 5324 QRegister result, | |
| 5325 Register tmp_hi, Register tmp_lo) { | |
| 5326 __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(result)); | |
| 5327 // Compare upper half. | |
| 5328 Label check_lower; | |
| 5329 __ CompareImmediate(tmp_hi, 0x00200000); | |
| 5330 __ b(overflow, GT); | |
| 5331 __ b(&check_lower, NE); | |
| 5332 | |
| 5333 __ CompareImmediate(tmp_lo, 0); | |
| 5334 __ b(overflow, HI); | |
| 5335 | |
| 5336 __ Bind(&check_lower); | |
| 5337 __ CompareImmediate(tmp_hi, -0x00200000); | |
| 5338 __ b(overflow, LT); | |
| 5339 // Anything in the lower part would make the number bigger than the lower | |
| 5340 // bound, so we are done. | |
| 5341 } | |
| 5342 | |
| 5343 | |
| 5187 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { | 5344 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
| 5188 UNIMPLEMENTED(); | 5345 const intptr_t kNumInputs = 1; |
| 5189 return NULL; | 5346 const intptr_t value_cid = value()->Type()->ToCid(); |
| 5347 const bool needs_writable_input = (value_cid != kMintCid); | |
| 5348 const bool needs_temp = (value_cid != kMintCid); | |
| 5349 const intptr_t kNumTemps = needs_temp ? 1 : 0; | |
| 5350 LocationSummary* summary = | |
| 5351 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 5352 summary->set_in(0, needs_writable_input | |
| 5353 ? Location::WritableRegister() | |
| 5354 : Location::RequiresRegister()); | |
| 5355 if (needs_temp) { | |
| 5356 summary->set_temp(0, Location::RequiresRegister()); | |
| 5357 } | |
| 5358 summary->set_out(Location::RequiresFpuRegister()); | |
| 5359 return summary; | |
| 5190 } | 5360 } |
| 5191 | 5361 |
| 5192 | 5362 |
| 5193 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5363 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5194 UNIMPLEMENTED(); | 5364 const intptr_t value_cid = value()->Type()->ToCid(); |
| 5365 const Register value = locs()->in(0).reg(); | |
| 5366 const QRegister result = locs()->out().fpu_reg(); | |
| 5367 | |
| 5368 __ Comment("UnboxIntegerInstr"); | |
| 5369 __ veorq(result, result, result); | |
| 5370 if (value_cid == kMintCid) { | |
| 5371 __ LoadDFromOffset(EvenDRegisterOf(result), value, | |
| 5372 Mint::value_offset() - kHeapObjectTag); | |
| 5373 } else if (value_cid == kSmiCid) { | |
| 5374 Register temp = locs()->temp(0).reg(); | |
| 5375 __ SmiUntag(value); | |
| 5376 __ LoadImmediate(temp, 0); | |
| 5377 __ CompareImmediate(value, 0); | |
| 5378 __ LoadImmediate(temp, -1, LT); | |
| 5379 __ vmovdrr(EvenDRegisterOf(result), value, temp); | |
|
regis
2014/03/20 20:39:35
Replace 3 instructions above with:
__ Lsl(temp,
zra
2014/03/20 23:49:25
Done.
| |
| 5380 } else { | |
| 5381 Register temp = locs()->temp(0).reg(); | |
| 5382 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptUnboxInteger); | |
| 5383 Label is_smi, done; | |
| 5384 __ tst(value, ShifterOperand(kSmiTagMask)); | |
| 5385 __ b(&is_smi, EQ); | |
| 5386 __ CompareClassId(value, kMintCid, temp); | |
| 5387 __ b(deopt, NE); | |
| 5388 | |
| 5389 // It's a Mint. | |
| 5390 __ LoadDFromOffset(EvenDRegisterOf(result), value, | |
| 5391 Mint::value_offset() - kHeapObjectTag); | |
| 5392 __ b(&done); | |
| 5393 | |
| 5394 // It's a Smi. | |
| 5395 __ Bind(&is_smi); | |
| 5396 __ SmiUntag(value); | |
| 5397 __ LoadImmediate(temp, 0); | |
| 5398 __ CompareImmediate(value, 0); | |
| 5399 __ LoadImmediate(temp, -1, LT); | |
|
regis
2014/03/20 20:39:35
ditto
zra
2014/03/20 23:49:25
Done.
| |
| 5400 __ vmovdrr(EvenDRegisterOf(result), value, temp); | |
| 5401 __ Bind(&done); | |
| 5402 } | |
| 5195 } | 5403 } |
| 5196 | 5404 |
| 5197 | 5405 |
| 5198 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { | 5406 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { |
| 5199 UNIMPLEMENTED(); | 5407 const intptr_t kNumInputs = 1; |
| 5200 return NULL; | 5408 const intptr_t kNumTemps = 2; |
| 5201 } | 5409 LocationSummary* summary = |
| 5410 new LocationSummary(kNumInputs, | |
| 5411 kNumTemps, | |
| 5412 LocationSummary::kCallOnSlowPath); | |
| 5413 summary->set_in(0, Location::RequiresFpuRegister()); | |
| 5414 summary->set_temp(0, Location::RequiresRegister()); | |
| 5415 summary->set_temp(1, Location::RequiresRegister()); | |
| 5416 summary->set_out(Location::RequiresRegister()); | |
| 5417 return summary; | |
| 5418 } | |
| 5419 | |
| 5420 | |
| 5421 class BoxIntegerSlowPath : public SlowPathCode { | |
| 5422 public: | |
| 5423 explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) | |
| 5424 : instruction_(instruction) { } | |
| 5425 | |
| 5426 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 5427 __ Comment("BoxIntegerSlowPath"); | |
| 5428 __ Bind(entry_label()); | |
| 5429 const Class& mint_class = | |
| 5430 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()); | |
| 5431 const Code& stub = | |
| 5432 Code::Handle(StubCode::GetAllocationStubForClass(mint_class)); | |
| 5433 const ExternalLabel label(mint_class.ToCString(), stub.EntryPoint()); | |
| 5434 | |
| 5435 LocationSummary* locs = instruction_->locs(); | |
| 5436 locs->live_registers()->Remove(locs->out()); | |
| 5437 | |
| 5438 compiler->SaveLiveRegisters(locs); | |
| 5439 compiler->GenerateCall(Scanner::kNoSourcePos, // No token position. | |
| 5440 &label, | |
| 5441 PcDescriptors::kOther, | |
| 5442 locs); | |
| 5443 __ mov(locs->out().reg(), ShifterOperand(R0)); | |
| 5444 compiler->RestoreLiveRegisters(locs); | |
| 5445 | |
| 5446 __ b(exit_label()); | |
| 5447 } | |
| 5448 | |
| 5449 private: | |
| 5450 BoxIntegerInstr* instruction_; | |
| 5451 }; | |
| 5202 | 5452 |
| 5203 | 5453 |
| 5204 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5454 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5205 UNIMPLEMENTED(); | 5455 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| 5456 compiler->AddSlowPathCode(slow_path); | |
| 5457 | |
| 5458 Register out_reg = locs()->out().reg(); | |
| 5459 QRegister value = locs()->in(0).fpu_reg(); | |
| 5460 DRegister dvalue0 = EvenDRegisterOf(value); | |
| 5461 Register lo = locs()->temp(0).reg(); | |
| 5462 Register hi = locs()->temp(1).reg(); | |
| 5463 | |
| 5464 // Unboxed operations produce smis or mint-sized values. | |
| 5465 // Check if value fits into a smi. | |
| 5466 __ Comment("BoxIntegerInstr"); | |
| 5467 Label not_smi, done, maybe_pos_smi, maybe_neg_smi, is_smi; | |
| 5468 __ vmovrrd(lo, hi, dvalue0); | |
| 5469 __ CompareImmediate(hi, 0); | |
| 5470 __ b(&maybe_pos_smi, EQ); | |
| 5471 | |
| 5472 __ CompareImmediate(hi, -1); | |
| 5473 __ b(&maybe_neg_smi, EQ); | |
| 5474 __ b(¬_smi); | |
| 5475 | |
| 5476 __ Bind(&maybe_pos_smi); | |
| 5477 __ CompareImmediate(lo, kSmiMax); | |
| 5478 __ b(&is_smi, LS); // unsigned lower or same. | |
| 5479 __ b(¬_smi); | |
| 5480 | |
| 5481 __ Bind(&maybe_neg_smi); | |
| 5482 __ CompareImmediate(lo, 0); | |
| 5483 __ b(¬_smi, GE); | |
| 5484 __ CompareImmediate(lo, kSmiMin); | |
| 5485 __ b(¬_smi, LT); | |
| 5486 | |
| 5487 // lo is a Smi. Tag it and return. | |
| 5488 __ Bind(&is_smi); | |
| 5489 __ SmiTag(lo); | |
| 5490 __ mov(out_reg, ShifterOperand(lo)); | |
| 5491 __ b(&done); | |
| 5492 | |
| 5493 // Not a smi. Box it. | |
| 5494 __ Bind(¬_smi); | |
| 5495 __ TryAllocate( | |
| 5496 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), | |
| 5497 slow_path->entry_label(), | |
| 5498 out_reg, | |
| 5499 lo); | |
| 5500 __ Bind(slow_path->exit_label()); | |
| 5501 __ StoreDToOffset(dvalue0, out_reg, Mint::value_offset() - kHeapObjectTag); | |
| 5502 __ Bind(&done); | |
| 5206 } | 5503 } |
| 5207 | 5504 |
| 5208 | 5505 |
| 5209 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { | 5506 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| 5210 UNIMPLEMENTED(); | 5507 const intptr_t kNumInputs = 2; |
| 5211 return NULL; | 5508 const intptr_t kNumTemps = |
| 5509 FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
| 5510 LocationSummary* summary = | |
| 5511 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 5512 summary->set_in(0, Location::RequiresFpuRegister()); | |
| 5513 summary->set_in(1, Location::RequiresFpuRegister()); | |
| 5514 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5515 summary->set_temp(0, Location::RequiresRegister()); | |
| 5516 summary->set_temp(1, Location::RequiresRegister()); | |
| 5517 } | |
| 5518 if ((op_kind() == Token::kADD) || (op_kind() == Token::kSUB)) { | |
| 5519 // Need another temp for checking for overflow. | |
| 5520 summary->AddTemp(Location::RequiresFpuRegister()); | |
| 5521 summary->AddTemp(Location::FpuRegisterLocation(Q7)); | |
| 5522 } | |
| 5523 summary->set_out(Location::RequiresFpuRegister()); | |
| 5524 return summary; | |
| 5212 } | 5525 } |
| 5213 | 5526 |
| 5214 | 5527 |
| 5215 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5528 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5216 UNIMPLEMENTED(); | 5529 QRegister left = locs()->in(0).fpu_reg(); |
| 5530 QRegister right = locs()->in(1).fpu_reg(); | |
| 5531 QRegister out = locs()->out().fpu_reg(); | |
| 5532 | |
| 5533 Label* deopt = NULL; | |
| 5534 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5535 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); | |
| 5536 } | |
| 5537 switch (op_kind()) { | |
| 5538 case Token::kBIT_AND: __ vandq(out, left, right); break; | |
| 5539 case Token::kBIT_OR: __ vorrq(out, left, right); break; | |
| 5540 case Token::kBIT_XOR: __ veorq(out, left, right); break; | |
| 5541 case Token::kADD: | |
| 5542 case Token::kSUB: { | |
| 5543 const intptr_t tmpidx = FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
| 5544 QRegister tmp = locs()->temp(tmpidx).fpu_reg(); | |
| 5545 QRegister ro = locs()->temp(tmpidx + 1).fpu_reg(); | |
| 5546 ASSERT(ro == Q7); | |
| 5547 if (!FLAG_throw_on_javascript_int_overflow) { | |
| 5548 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); | |
| 5549 } | |
| 5550 if (op_kind() == Token::kADD) { | |
| 5551 __ vaddqi(kWordPair, out, left, right); | |
| 5552 } else { | |
| 5553 ASSERT(op_kind() == Token::kSUB); | |
| 5554 __ vsubqi(kWordPair, out, left, right); | |
| 5555 } | |
| 5556 __ veorq(ro, out, left); | |
| 5557 __ veorq(tmp, left, right); | |
| 5558 __ vandq(ro, tmp, ro); | |
| 5559 __ vmovrs(TMP, OddSRegisterOf(EvenDRegisterOf(ro))); | |
| 5560 // If TMP < 0, there was overflow. | |
| 5561 __ cmp(TMP, ShifterOperand(0)); | |
| 5562 __ b(deopt, LT); | |
| 5563 break; | |
| 5564 } | |
| 5565 default: UNREACHABLE(); break; | |
| 5566 } | |
| 5567 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5568 Register tmp1 = locs()->temp(0).reg(); | |
| 5569 Register tmp2 = locs()->temp(1).reg(); | |
| 5570 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
| 5571 } | |
| 5217 } | 5572 } |
| 5218 | 5573 |
| 5219 | 5574 |
| 5220 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { | 5575 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { |
| 5221 UNIMPLEMENTED(); | 5576 const intptr_t kNumInputs = 2; |
| 5222 return NULL; | 5577 const intptr_t kNumTemps = |
| 5578 FLAG_throw_on_javascript_int_overflow ? 2 : 1; | |
| 5579 LocationSummary* summary = | |
| 5580 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 5581 summary->set_in(0, Location::RequiresFpuRegister()); | |
| 5582 summary->set_in(1, Location::WritableRegister()); | |
| 5583 summary->set_temp(0, Location::FpuRegisterLocation(Q7)); | |
| 5584 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5585 summary->set_temp(1, Location::RequiresRegister()); | |
| 5586 } | |
| 5587 summary->set_out(Location::RequiresFpuRegister()); | |
| 5588 return summary; | |
| 5223 } | 5589 } |
| 5224 | 5590 |
| 5225 | 5591 |
| 5226 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5592 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5227 UNIMPLEMENTED(); | 5593 QRegister value = locs()->in(0).fpu_reg(); |
| 5594 Register shift = locs()->in(1).reg(); | |
| 5595 QRegister temp = locs()->temp(0).fpu_reg(); | |
| 5596 ASSERT(temp == Q7); | |
| 5597 QRegister out = locs()->out().fpu_reg(); | |
| 5598 DRegister dtemp0 = EvenDRegisterOf(temp); | |
| 5599 SRegister stemp0 = EvenSRegisterOf(dtemp0); | |
| 5600 SRegister stemp1 = OddSRegisterOf(dtemp0); | |
| 5601 | |
| 5602 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptShiftMintOp); | |
| 5603 Label done; | |
| 5604 | |
| 5605 __ CompareImmediate(shift, 0); | |
| 5606 __ vmovq(out, value); | |
| 5607 __ b(&done, EQ); | |
| 5608 __ SmiUntag(shift); | |
| 5609 | |
| 5610 // vshlq takes the shift value from low byte. Deopt if shift is | |
| 5611 // outside of [0, 127]. | |
| 5612 __ CompareImmediate(shift, 127); | |
| 5613 __ b(deopt, GT); | |
| 5614 __ CompareImmediate(shift, 0); | |
| 5615 __ b(deopt, LT); | |
| 5616 | |
| 5617 __ veorq(temp, temp, temp); // Zero out temp. | |
| 5618 switch (op_kind()) { | |
| 5619 case Token::kSHR: { | |
| 5620 __ rsb(shift, shift, ShifterOperand(0)); // Negate shift. | |
| 5621 __ vmovsr(stemp0, shift); // Move the shift into the low S register. | |
| 5622 __ vshlqi(kWordPair, out, value, temp); | |
| 5623 break; | |
| 5624 } | |
| 5625 case Token::kSHL: { | |
| 5626 __ vmovsr(stemp0, shift); // Move the shift into the low S register. | |
| 5627 __ vshlqu(kWordPair, out, value, temp); | |
| 5628 | |
| 5629 // check for overflow by shifting back and comparing. | |
| 5630 __ rsb(shift, shift, ShifterOperand(0)); | |
| 5631 __ vmovsr(stemp0, shift); | |
| 5632 __ vshlqi(kWordPair, temp, out, temp); | |
| 5633 __ vceqqi(kWord, temp, temp, value); | |
| 5634 // Low 64 bits of temp should be all 1's, otherwise temp != value and | |
| 5635 // we deopt. | |
| 5636 __ vmovrs(shift, stemp0); | |
| 5637 __ CompareImmediate(shift, -1); | |
| 5638 __ b(deopt, NE); | |
| 5639 __ vmovrs(shift, stemp1); | |
| 5640 __ CompareImmediate(shift, -1); | |
| 5641 __ b(deopt, NE); | |
| 5642 break; | |
| 5643 } | |
| 5644 default: | |
| 5645 UNREACHABLE(); | |
| 5646 break; | |
| 5647 } | |
| 5648 | |
| 5649 __ Bind(&done); | |
| 5650 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5651 Register tmp1 = locs()->in(1).reg(); | |
| 5652 Register tmp2 = locs()->temp(1).reg(); | |
| 5653 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
| 5654 } | |
| 5228 } | 5655 } |
| 5229 | 5656 |
| 5230 | 5657 |
| 5231 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { | 5658 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { |
| 5232 UNIMPLEMENTED(); | 5659 const intptr_t kNumInputs = 1; |
| 5233 return NULL; | 5660 const intptr_t kNumTemps = |
| 5661 FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
| 5662 LocationSummary* summary = | |
| 5663 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 5664 summary->set_in(0, Location::RequiresFpuRegister()); | |
| 5665 summary->set_out(Location::RequiresFpuRegister()); | |
| 5666 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5667 summary->set_temp(0, Location::RequiresRegister()); | |
| 5668 summary->set_temp(1, Location::RequiresRegister()); | |
| 5669 } | |
| 5670 return summary; | |
| 5234 } | 5671 } |
| 5235 | 5672 |
| 5236 | 5673 |
| 5237 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5674 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5238 UNIMPLEMENTED(); | 5675 ASSERT(op_kind() == Token::kBIT_NOT); |
| 5239 } | 5676 QRegister value = locs()->in(0).fpu_reg(); |
| 5240 | 5677 QRegister out = locs()->out().fpu_reg(); |
| 5241 | 5678 Label* deopt = NULL; |
| 5679 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5680 deopt = compiler->AddDeoptStub(deopt_id(), | |
| 5681 kDeoptUnaryMintOp); | |
| 5682 } | |
| 5683 __ vmvnq(out, value); | |
| 5684 if (FLAG_throw_on_javascript_int_overflow) { | |
| 5685 Register tmp1 = locs()->temp(0).reg(); | |
| 5686 Register tmp2 = locs()->temp(1).reg(); | |
| 5687 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
| 5688 } | |
| 5689 } | |
| 5690 | |
| 5691 | |
| 5242 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { | 5692 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { |
| 5243 return new LocationSummary(0, 0, LocationSummary::kCall); | 5693 return new LocationSummary(0, 0, LocationSummary::kCall); |
| 5244 } | 5694 } |
| 5245 | 5695 |
| 5246 | 5696 |
| 5247 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5697 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5248 compiler->GenerateRuntimeCall(token_pos(), | 5698 compiler->GenerateRuntimeCall(token_pos(), |
| 5249 deopt_id(), | 5699 deopt_id(), |
| 5250 kThrowRuntimeEntry, | 5700 kThrowRuntimeEntry, |
| 5251 1, | 5701 1, |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5437 compiler->GenerateCall(token_pos(), | 5887 compiler->GenerateCall(token_pos(), |
| 5438 &label, | 5888 &label, |
| 5439 PcDescriptors::kOther, | 5889 PcDescriptors::kOther, |
| 5440 locs()); | 5890 locs()); |
| 5441 __ Drop(ArgumentCount()); // Discard arguments. | 5891 __ Drop(ArgumentCount()); // Discard arguments. |
| 5442 } | 5892 } |
| 5443 | 5893 |
| 5444 } // namespace dart | 5894 } // namespace dart |
| 5445 | 5895 |
| 5446 #endif // defined TARGET_ARCH_ARM | 5896 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |