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(0, Location::RequiresRegister()); | 343 locs->set_out(0, 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(0, Location::RequiresRegister()); | 352 locs->set_out(0, 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(0).reg(); | 595 Register result = locs()->out(0).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(0, Location::RequiresRegister()); | 702 summary->set_out(0, 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(0).reg(); | 725 Register result = locs()->out(0).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(0).fpu_reg(); | 1084 QRegister result = locs()->out(0).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 // Sign-extend into idx. |
| 1095 __ Asr(idx, TMP, 31); |
| 1096 __ vmovdrr(dresult0, TMP, idx); |
977 break; | 1097 break; |
978 case kTypedDataUint32ArrayCid: | 1098 case kTypedDataUint32ArrayCid: |
979 UNIMPLEMENTED(); | 1099 __ veorq(result, result, result); |
| 1100 __ ldr(TMP, element_address); |
| 1101 // Re-use the index register so we don't have to require a low-numbered |
| 1102 // Q register. |
| 1103 __ LoadImmediate(idx, 0); |
| 1104 __ vmovdrr(dresult0, TMP, idx); |
980 break; | 1105 break; |
981 case kTypedDataFloat32ArrayCid: | 1106 case kTypedDataFloat32ArrayCid: |
982 // Load single precision float. | 1107 // Load single precision float. |
983 // vldrs does not support indexed addressing. | 1108 // vldrs does not support indexed addressing. |
984 __ add(index.reg(), index.reg(), ShifterOperand(array)); | 1109 __ add(index.reg(), index.reg(), ShifterOperand(array)); |
985 element_address = Address(index.reg(), 0); | 1110 element_address = Address(index.reg(), 0); |
986 __ vldrs(EvenSRegisterOf(dresult0), element_address); | 1111 __ vldrs(EvenSRegisterOf(dresult0), element_address); |
987 break; | 1112 break; |
988 case kTypedDataFloat64ArrayCid: | 1113 case kTypedDataFloat64ArrayCid: |
989 // vldrd does not support indexed addressing. | 1114 // 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. | 1159 // Verify that the signed value in 'result' can fit inside a Smi. |
1035 __ CompareImmediate(result, 0xC0000000); | 1160 __ CompareImmediate(result, 0xC0000000); |
1036 __ b(deopt, MI); | 1161 __ b(deopt, MI); |
1037 __ SmiTag(result); | 1162 __ SmiTag(result); |
1038 } | 1163 } |
1039 break; | 1164 break; |
1040 case kTypedDataUint32ArrayCid: { | 1165 case kTypedDataUint32ArrayCid: { |
1041 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load); | 1166 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load); |
1042 __ ldr(result, element_address); | 1167 __ ldr(result, element_address); |
1043 // Verify that the unsigned value in 'result' can fit inside a Smi. | 1168 // Verify that the unsigned value in 'result' can fit inside a Smi. |
1044 __ tst(result, ShifterOperand(0xC0000000)); | 1169 __ TestImmediate(result, 0xC0000000); |
1045 __ b(deopt, NE); | 1170 __ b(deopt, NE); |
1046 __ SmiTag(result); | 1171 __ SmiTag(result); |
1047 } | 1172 } |
1048 break; | 1173 break; |
1049 default: | 1174 default: |
1050 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); | 1175 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); |
1051 __ ldr(result, element_address); | 1176 __ ldr(result, element_address); |
1052 break; | 1177 break; |
1053 } | 1178 } |
1054 } | 1179 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 : Location::RegisterOrConstant(value())); | 1232 : Location::RegisterOrConstant(value())); |
1108 break; | 1233 break; |
1109 case kExternalTypedDataUint8ArrayCid: | 1234 case kExternalTypedDataUint8ArrayCid: |
1110 case kExternalTypedDataUint8ClampedArrayCid: | 1235 case kExternalTypedDataUint8ClampedArrayCid: |
1111 case kTypedDataInt8ArrayCid: | 1236 case kTypedDataInt8ArrayCid: |
1112 case kTypedDataUint8ArrayCid: | 1237 case kTypedDataUint8ArrayCid: |
1113 case kTypedDataUint8ClampedArrayCid: | 1238 case kTypedDataUint8ClampedArrayCid: |
1114 case kOneByteStringCid: | 1239 case kOneByteStringCid: |
1115 case kTypedDataInt16ArrayCid: | 1240 case kTypedDataInt16ArrayCid: |
1116 case kTypedDataUint16ArrayCid: | 1241 case kTypedDataUint16ArrayCid: |
| 1242 locs->set_in(2, Location::WritableRegister()); |
| 1243 break; |
1117 case kTypedDataInt32ArrayCid: | 1244 case kTypedDataInt32ArrayCid: |
1118 case kTypedDataUint32ArrayCid: | 1245 case kTypedDataUint32ArrayCid: |
1119 locs->set_in(2, Location::WritableRegister()); | 1246 // Mints are stored in Q registers. For smis, use a writable register |
| 1247 // because the value must be untagged before storing. |
| 1248 locs->set_in(2, value()->IsSmiValue() |
| 1249 ? Location::WritableRegister() |
| 1250 : Location::FpuRegisterLocation(Q7)); |
1120 break; | 1251 break; |
1121 case kTypedDataFloat32ArrayCid: | 1252 case kTypedDataFloat32ArrayCid: |
1122 // Need low register (<= Q7). | 1253 // Need low register (<= Q7). |
1123 locs->set_in(2, Location::FpuRegisterLocation(Q7)); | 1254 locs->set_in(2, Location::FpuRegisterLocation(Q7)); |
1124 break; | 1255 break; |
1125 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. | 1256 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. |
1126 case kTypedDataInt32x4ArrayCid: | 1257 case kTypedDataInt32x4ArrayCid: |
1127 case kTypedDataFloat32x4ArrayCid: | 1258 case kTypedDataFloat32x4ArrayCid: |
1128 case kTypedDataFloat64x2ArrayCid: | 1259 case kTypedDataFloat64x2ArrayCid: |
1129 locs->set_in(2, Location::RequiresFpuRegister()); | 1260 locs->set_in(2, Location::RequiresFpuRegister()); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1239 break; | 1370 break; |
1240 } | 1371 } |
1241 case kTypedDataInt32ArrayCid: | 1372 case kTypedDataInt32ArrayCid: |
1242 case kTypedDataUint32ArrayCid: { | 1373 case kTypedDataUint32ArrayCid: { |
1243 if (value()->IsSmiValue()) { | 1374 if (value()->IsSmiValue()) { |
1244 ASSERT(RequiredInputRepresentation(2) == kTagged); | 1375 ASSERT(RequiredInputRepresentation(2) == kTagged); |
1245 Register value = locs()->in(2).reg(); | 1376 Register value = locs()->in(2).reg(); |
1246 __ SmiUntag(value); | 1377 __ SmiUntag(value); |
1247 __ str(value, element_address); | 1378 __ str(value, element_address); |
1248 } else { | 1379 } else { |
1249 UNIMPLEMENTED(); | 1380 ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); |
| 1381 QRegister value = locs()->in(2).fpu_reg(); |
| 1382 ASSERT(value == Q7); |
| 1383 __ vmovrs(TMP, EvenSRegisterOf(EvenDRegisterOf(value))); |
| 1384 __ str(TMP, element_address); |
1250 } | 1385 } |
1251 break; | 1386 break; |
1252 } | 1387 } |
1253 case kTypedDataFloat32ArrayCid: { | 1388 case kTypedDataFloat32ArrayCid: { |
1254 SRegister value = | 1389 SRegister value = |
1255 EvenSRegisterOf(EvenDRegisterOf(locs()->in(2).fpu_reg())); | 1390 EvenSRegisterOf(EvenDRegisterOf(locs()->in(2).fpu_reg())); |
1256 __ add(index.reg(), index.reg(), ShifterOperand(array)); | 1391 __ add(index.reg(), index.reg(), ShifterOperand(array)); |
1257 __ StoreSToOffset(value, index.reg(), 0); | 1392 __ StoreSToOffset(value, index.reg(), 0); |
1258 break; | 1393 break; |
1259 } | 1394 } |
(...skipping 2450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3710 QRegister right = locs()->in(1).fpu_reg(); | 3845 QRegister right = locs()->in(1).fpu_reg(); |
3711 QRegister result = locs()->out(0).fpu_reg(); | 3846 QRegister result = locs()->out(0).fpu_reg(); |
3712 | 3847 |
3713 switch (op_kind()) { | 3848 switch (op_kind()) { |
3714 case MethodRecognizer::kFloat32x4Equal: | 3849 case MethodRecognizer::kFloat32x4Equal: |
3715 __ vceqqs(result, left, right); | 3850 __ vceqqs(result, left, right); |
3716 break; | 3851 break; |
3717 case MethodRecognizer::kFloat32x4NotEqual: | 3852 case MethodRecognizer::kFloat32x4NotEqual: |
3718 __ vceqqs(result, left, right); | 3853 __ vceqqs(result, left, right); |
3719 // Invert the result. | 3854 // Invert the result. |
3720 __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. | 3855 __ vmvnq(result, result); |
3721 __ vornq(result, QTMP, result); // result <- ~result. | |
3722 break; | 3856 break; |
3723 case MethodRecognizer::kFloat32x4GreaterThan: | 3857 case MethodRecognizer::kFloat32x4GreaterThan: |
3724 __ vcgtqs(result, left, right); | 3858 __ vcgtqs(result, left, right); |
3725 break; | 3859 break; |
3726 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | 3860 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: |
3727 __ vcgeqs(result, left, right); | 3861 __ vcgeqs(result, left, right); |
3728 break; | 3862 break; |
3729 case MethodRecognizer::kFloat32x4LessThan: | 3863 case MethodRecognizer::kFloat32x4LessThan: |
3730 __ vcgtqs(result, right, left); | 3864 __ vcgtqs(result, right, left); |
3731 break; | 3865 break; |
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4360 void Int32x4SelectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4494 void Int32x4SelectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
4361 QRegister mask = locs()->in(0).fpu_reg(); | 4495 QRegister mask = locs()->in(0).fpu_reg(); |
4362 QRegister trueValue = locs()->in(1).fpu_reg(); | 4496 QRegister trueValue = locs()->in(1).fpu_reg(); |
4363 QRegister falseValue = locs()->in(2).fpu_reg(); | 4497 QRegister falseValue = locs()->in(2).fpu_reg(); |
4364 QRegister out = locs()->out(0).fpu_reg(); | 4498 QRegister out = locs()->out(0).fpu_reg(); |
4365 QRegister temp = locs()->temp(0).fpu_reg(); | 4499 QRegister temp = locs()->temp(0).fpu_reg(); |
4366 | 4500 |
4367 // Copy mask. | 4501 // Copy mask. |
4368 __ vmovq(temp, mask); | 4502 __ vmovq(temp, mask); |
4369 // Invert it. | 4503 // Invert it. |
4370 __ veorq(QTMP, QTMP, QTMP); // QTMP <- 0. | 4504 __ vmvnq(temp, temp); |
4371 __ vornq(temp, QTMP, temp); // temp <- ~temp. | |
4372 // mask = mask & trueValue. | 4505 // mask = mask & trueValue. |
4373 __ vandq(mask, mask, trueValue); | 4506 __ vandq(mask, mask, trueValue); |
4374 // temp = temp & falseValue. | 4507 // temp = temp & falseValue. |
4375 __ vandq(temp, temp, falseValue); | 4508 __ vandq(temp, temp, falseValue); |
4376 // out = mask | temp. | 4509 // out = mask | temp. |
4377 __ vorrq(out, mask, temp); | 4510 __ vorrq(out, mask, temp); |
4378 } | 4511 } |
4379 | 4512 |
4380 | 4513 |
4381 LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const { | 4514 LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const { |
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5177 __ b(deopt, CS); | 5310 __ b(deopt, CS); |
5178 } else { | 5311 } else { |
5179 Register length = length_loc.reg(); | 5312 Register length = length_loc.reg(); |
5180 Register index = index_loc.reg(); | 5313 Register index = index_loc.reg(); |
5181 __ cmp(index, ShifterOperand(length)); | 5314 __ cmp(index, ShifterOperand(length)); |
5182 __ b(deopt, CS); | 5315 __ b(deopt, CS); |
5183 } | 5316 } |
5184 } | 5317 } |
5185 | 5318 |
5186 | 5319 |
| 5320 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
| 5321 Label* overflow, |
| 5322 QRegister result, |
| 5323 Register tmp_hi, Register tmp_lo) { |
| 5324 __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(result)); |
| 5325 // Compare upper half. |
| 5326 Label check_lower; |
| 5327 __ CompareImmediate(tmp_hi, 0x00200000); |
| 5328 __ b(overflow, GT); |
| 5329 __ b(&check_lower, NE); |
| 5330 |
| 5331 __ CompareImmediate(tmp_lo, 0); |
| 5332 __ b(overflow, HI); |
| 5333 |
| 5334 __ Bind(&check_lower); |
| 5335 __ CompareImmediate(tmp_hi, -0x00200000); |
| 5336 __ b(overflow, LT); |
| 5337 // Anything in the lower part would make the number bigger than the lower |
| 5338 // bound, so we are done. |
| 5339 } |
| 5340 |
| 5341 |
5187 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { | 5342 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
5188 UNIMPLEMENTED(); | 5343 const intptr_t kNumInputs = 1; |
5189 return NULL; | 5344 const intptr_t value_cid = value()->Type()->ToCid(); |
| 5345 const bool needs_writable_input = (value_cid != kMintCid); |
| 5346 const bool needs_temp = (value_cid != kMintCid); |
| 5347 const intptr_t kNumTemps = needs_temp ? 1 : 0; |
| 5348 LocationSummary* summary = |
| 5349 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 5350 summary->set_in(0, needs_writable_input |
| 5351 ? Location::WritableRegister() |
| 5352 : Location::RequiresRegister()); |
| 5353 if (needs_temp) { |
| 5354 summary->set_temp(0, Location::RequiresRegister()); |
| 5355 } |
| 5356 summary->set_out(0, Location::RequiresFpuRegister()); |
| 5357 return summary; |
5190 } | 5358 } |
5191 | 5359 |
5192 | 5360 |
5193 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5361 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5194 UNIMPLEMENTED(); | 5362 const intptr_t value_cid = value()->Type()->ToCid(); |
| 5363 const Register value = locs()->in(0).reg(); |
| 5364 const QRegister result = locs()->out(0).fpu_reg(); |
| 5365 |
| 5366 __ Comment("UnboxIntegerInstr"); |
| 5367 __ veorq(result, result, result); |
| 5368 if (value_cid == kMintCid) { |
| 5369 __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| 5370 Mint::value_offset() - kHeapObjectTag); |
| 5371 } else if (value_cid == kSmiCid) { |
| 5372 Register temp = locs()->temp(0).reg(); |
| 5373 __ SmiUntag(value); |
| 5374 // Sign extend value into temp. |
| 5375 __ Asr(temp, value, 31); |
| 5376 __ vmovdrr(EvenDRegisterOf(result), value, temp); |
| 5377 } else { |
| 5378 Register temp = locs()->temp(0).reg(); |
| 5379 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptUnboxInteger); |
| 5380 Label is_smi, done; |
| 5381 __ tst(value, ShifterOperand(kSmiTagMask)); |
| 5382 __ b(&is_smi, EQ); |
| 5383 __ CompareClassId(value, kMintCid, temp); |
| 5384 __ b(deopt, NE); |
| 5385 |
| 5386 // It's a Mint. |
| 5387 __ LoadDFromOffset(EvenDRegisterOf(result), value, |
| 5388 Mint::value_offset() - kHeapObjectTag); |
| 5389 __ b(&done); |
| 5390 |
| 5391 // It's a Smi. |
| 5392 __ Bind(&is_smi); |
| 5393 __ SmiUntag(value); |
| 5394 // Sign extend into temp. |
| 5395 __ Asr(temp, value, 31); |
| 5396 __ vmovdrr(EvenDRegisterOf(result), value, temp); |
| 5397 __ Bind(&done); |
| 5398 } |
5195 } | 5399 } |
5196 | 5400 |
5197 | 5401 |
5198 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { | 5402 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { |
5199 UNIMPLEMENTED(); | 5403 const intptr_t kNumInputs = 1; |
5200 return NULL; | 5404 const intptr_t kNumTemps = 2; |
5201 } | 5405 LocationSummary* summary = |
| 5406 new LocationSummary(kNumInputs, |
| 5407 kNumTemps, |
| 5408 LocationSummary::kCallOnSlowPath); |
| 5409 summary->set_in(0, Location::RequiresFpuRegister()); |
| 5410 summary->set_temp(0, Location::RequiresRegister()); |
| 5411 summary->set_temp(1, Location::RequiresRegister()); |
| 5412 summary->set_out(0, Location::RequiresRegister()); |
| 5413 return summary; |
| 5414 } |
| 5415 |
| 5416 |
| 5417 class BoxIntegerSlowPath : public SlowPathCode { |
| 5418 public: |
| 5419 explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) |
| 5420 : instruction_(instruction) { } |
| 5421 |
| 5422 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5423 __ Comment("BoxIntegerSlowPath"); |
| 5424 __ Bind(entry_label()); |
| 5425 const Class& mint_class = |
| 5426 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()); |
| 5427 const Code& stub = |
| 5428 Code::Handle(StubCode::GetAllocationStubForClass(mint_class)); |
| 5429 const ExternalLabel label(mint_class.ToCString(), stub.EntryPoint()); |
| 5430 |
| 5431 LocationSummary* locs = instruction_->locs(); |
| 5432 locs->live_registers()->Remove(locs->out(0)); |
| 5433 |
| 5434 compiler->SaveLiveRegisters(locs); |
| 5435 compiler->GenerateCall(Scanner::kNoSourcePos, // No token position. |
| 5436 &label, |
| 5437 PcDescriptors::kOther, |
| 5438 locs); |
| 5439 __ mov(locs->out(0).reg(), ShifterOperand(R0)); |
| 5440 compiler->RestoreLiveRegisters(locs); |
| 5441 |
| 5442 __ b(exit_label()); |
| 5443 } |
| 5444 |
| 5445 private: |
| 5446 BoxIntegerInstr* instruction_; |
| 5447 }; |
5202 | 5448 |
5203 | 5449 |
5204 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5450 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5205 UNIMPLEMENTED(); | 5451 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| 5452 compiler->AddSlowPathCode(slow_path); |
| 5453 |
| 5454 Register out_reg = locs()->out(0).reg(); |
| 5455 QRegister value = locs()->in(0).fpu_reg(); |
| 5456 DRegister dvalue0 = EvenDRegisterOf(value); |
| 5457 Register lo = locs()->temp(0).reg(); |
| 5458 Register hi = locs()->temp(1).reg(); |
| 5459 |
| 5460 // Unboxed operations produce smis or mint-sized values. |
| 5461 // Check if value fits into a smi. |
| 5462 __ Comment("BoxIntegerInstr"); |
| 5463 Label not_smi, done, maybe_pos_smi, maybe_neg_smi, is_smi; |
| 5464 __ vmovrrd(lo, hi, dvalue0); |
| 5465 __ CompareImmediate(hi, 0); |
| 5466 __ b(&maybe_pos_smi, EQ); |
| 5467 |
| 5468 __ CompareImmediate(hi, -1); |
| 5469 __ b(&maybe_neg_smi, EQ); |
| 5470 __ b(¬_smi); |
| 5471 |
| 5472 __ Bind(&maybe_pos_smi); |
| 5473 __ CompareImmediate(lo, kSmiMax); |
| 5474 __ b(&is_smi, LS); // unsigned lower or same. |
| 5475 __ b(¬_smi); |
| 5476 |
| 5477 __ Bind(&maybe_neg_smi); |
| 5478 __ CompareImmediate(lo, 0); |
| 5479 __ b(¬_smi, GE); |
| 5480 __ CompareImmediate(lo, kSmiMin); |
| 5481 __ b(¬_smi, LT); |
| 5482 |
| 5483 // lo is a Smi. Tag it and return. |
| 5484 __ Bind(&is_smi); |
| 5485 __ SmiTag(lo); |
| 5486 __ mov(out_reg, ShifterOperand(lo)); |
| 5487 __ b(&done); |
| 5488 |
| 5489 // Not a smi. Box it. |
| 5490 __ Bind(¬_smi); |
| 5491 __ TryAllocate( |
| 5492 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
| 5493 slow_path->entry_label(), |
| 5494 out_reg, |
| 5495 lo); |
| 5496 __ Bind(slow_path->exit_label()); |
| 5497 __ StoreDToOffset(dvalue0, out_reg, Mint::value_offset() - kHeapObjectTag); |
| 5498 __ Bind(&done); |
5206 } | 5499 } |
5207 | 5500 |
5208 | 5501 |
5209 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { | 5502 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { |
5210 UNIMPLEMENTED(); | 5503 const intptr_t kNumInputs = 2; |
5211 return NULL; | 5504 const intptr_t kNumTemps = |
| 5505 FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| 5506 LocationSummary* summary = |
| 5507 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 5508 summary->set_in(0, Location::RequiresFpuRegister()); |
| 5509 summary->set_in(1, Location::RequiresFpuRegister()); |
| 5510 if (FLAG_throw_on_javascript_int_overflow) { |
| 5511 summary->set_temp(0, Location::RequiresRegister()); |
| 5512 summary->set_temp(1, Location::RequiresRegister()); |
| 5513 } |
| 5514 if ((op_kind() == Token::kADD) || (op_kind() == Token::kSUB)) { |
| 5515 // Need another temp for checking for overflow. |
| 5516 summary->AddTemp(Location::RequiresFpuRegister()); |
| 5517 summary->AddTemp(Location::FpuRegisterLocation(Q7)); |
| 5518 } |
| 5519 summary->set_out(0, Location::RequiresFpuRegister()); |
| 5520 return summary; |
5212 } | 5521 } |
5213 | 5522 |
5214 | 5523 |
5215 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5524 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5216 UNIMPLEMENTED(); | 5525 QRegister left = locs()->in(0).fpu_reg(); |
| 5526 QRegister right = locs()->in(1).fpu_reg(); |
| 5527 QRegister out = locs()->out(0).fpu_reg(); |
| 5528 |
| 5529 Label* deopt = NULL; |
| 5530 if (FLAG_throw_on_javascript_int_overflow) { |
| 5531 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); |
| 5532 } |
| 5533 switch (op_kind()) { |
| 5534 case Token::kBIT_AND: __ vandq(out, left, right); break; |
| 5535 case Token::kBIT_OR: __ vorrq(out, left, right); break; |
| 5536 case Token::kBIT_XOR: __ veorq(out, left, right); break; |
| 5537 case Token::kADD: |
| 5538 case Token::kSUB: { |
| 5539 const intptr_t tmpidx = FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| 5540 QRegister tmp = locs()->temp(tmpidx).fpu_reg(); |
| 5541 QRegister ro = locs()->temp(tmpidx + 1).fpu_reg(); |
| 5542 ASSERT(ro == Q7); |
| 5543 if (!FLAG_throw_on_javascript_int_overflow) { |
| 5544 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryMintOp); |
| 5545 } |
| 5546 if (op_kind() == Token::kADD) { |
| 5547 __ vaddqi(kWordPair, out, left, right); |
| 5548 } else { |
| 5549 ASSERT(op_kind() == Token::kSUB); |
| 5550 __ vsubqi(kWordPair, out, left, right); |
| 5551 } |
| 5552 __ veorq(ro, out, left); |
| 5553 __ veorq(tmp, left, right); |
| 5554 __ vandq(ro, tmp, ro); |
| 5555 __ vmovrs(TMP, OddSRegisterOf(EvenDRegisterOf(ro))); |
| 5556 // If TMP < 0, there was overflow. |
| 5557 __ cmp(TMP, ShifterOperand(0)); |
| 5558 __ b(deopt, LT); |
| 5559 break; |
| 5560 } |
| 5561 default: UNREACHABLE(); break; |
| 5562 } |
| 5563 if (FLAG_throw_on_javascript_int_overflow) { |
| 5564 Register tmp1 = locs()->temp(0).reg(); |
| 5565 Register tmp2 = locs()->temp(1).reg(); |
| 5566 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| 5567 } |
5217 } | 5568 } |
5218 | 5569 |
5219 | 5570 |
5220 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { | 5571 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { |
5221 UNIMPLEMENTED(); | 5572 const intptr_t kNumInputs = 2; |
5222 return NULL; | 5573 const intptr_t kNumTemps = |
| 5574 FLAG_throw_on_javascript_int_overflow ? 2 : 1; |
| 5575 LocationSummary* summary = |
| 5576 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 5577 summary->set_in(0, Location::RequiresFpuRegister()); |
| 5578 summary->set_in(1, Location::WritableRegister()); |
| 5579 summary->set_temp(0, Location::FpuRegisterLocation(Q7)); |
| 5580 if (FLAG_throw_on_javascript_int_overflow) { |
| 5581 summary->set_temp(1, Location::RequiresRegister()); |
| 5582 } |
| 5583 summary->set_out(0, Location::RequiresFpuRegister()); |
| 5584 return summary; |
5223 } | 5585 } |
5224 | 5586 |
5225 | 5587 |
5226 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5588 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5227 UNIMPLEMENTED(); | 5589 QRegister value = locs()->in(0).fpu_reg(); |
| 5590 Register shift = locs()->in(1).reg(); |
| 5591 QRegister temp = locs()->temp(0).fpu_reg(); |
| 5592 ASSERT(temp == Q7); |
| 5593 QRegister out = locs()->out(0).fpu_reg(); |
| 5594 DRegister dtemp0 = EvenDRegisterOf(temp); |
| 5595 SRegister stemp0 = EvenSRegisterOf(dtemp0); |
| 5596 SRegister stemp1 = OddSRegisterOf(dtemp0); |
| 5597 |
| 5598 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptShiftMintOp); |
| 5599 Label done; |
| 5600 |
| 5601 __ CompareImmediate(shift, 0); |
| 5602 __ vmovq(out, value); |
| 5603 __ b(&done, EQ); |
| 5604 __ SmiUntag(shift); |
| 5605 |
| 5606 // vshlq takes the shift value from low byte. Deopt if shift is |
| 5607 // outside of [0, 127]. |
| 5608 __ CompareImmediate(shift, 127); |
| 5609 __ b(deopt, GT); |
| 5610 __ CompareImmediate(shift, 0); |
| 5611 __ b(deopt, LT); |
| 5612 |
| 5613 __ veorq(temp, temp, temp); // Zero out temp. |
| 5614 switch (op_kind()) { |
| 5615 case Token::kSHR: { |
| 5616 __ rsb(shift, shift, ShifterOperand(0)); // Negate shift. |
| 5617 __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
| 5618 __ vshlqi(kWordPair, out, value, temp); |
| 5619 break; |
| 5620 } |
| 5621 case Token::kSHL: { |
| 5622 __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
| 5623 __ vshlqu(kWordPair, out, value, temp); |
| 5624 |
| 5625 // check for overflow by shifting back and comparing. |
| 5626 __ rsb(shift, shift, ShifterOperand(0)); |
| 5627 __ vmovsr(stemp0, shift); |
| 5628 __ vshlqi(kWordPair, temp, out, temp); |
| 5629 __ vceqqi(kWord, temp, temp, value); |
| 5630 // Low 64 bits of temp should be all 1's, otherwise temp != value and |
| 5631 // we deopt. |
| 5632 __ vmovrs(shift, stemp0); |
| 5633 __ CompareImmediate(shift, -1); |
| 5634 __ b(deopt, NE); |
| 5635 __ vmovrs(shift, stemp1); |
| 5636 __ CompareImmediate(shift, -1); |
| 5637 __ b(deopt, NE); |
| 5638 break; |
| 5639 } |
| 5640 default: |
| 5641 UNREACHABLE(); |
| 5642 break; |
| 5643 } |
| 5644 |
| 5645 __ Bind(&done); |
| 5646 if (FLAG_throw_on_javascript_int_overflow) { |
| 5647 Register tmp1 = locs()->in(1).reg(); |
| 5648 Register tmp2 = locs()->temp(1).reg(); |
| 5649 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| 5650 } |
5228 } | 5651 } |
5229 | 5652 |
5230 | 5653 |
5231 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { | 5654 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { |
5232 UNIMPLEMENTED(); | 5655 const intptr_t kNumInputs = 1; |
5233 return NULL; | 5656 const intptr_t kNumTemps = |
| 5657 FLAG_throw_on_javascript_int_overflow ? 2 : 0; |
| 5658 LocationSummary* summary = |
| 5659 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 5660 summary->set_in(0, Location::RequiresFpuRegister()); |
| 5661 summary->set_out(0, Location::RequiresFpuRegister()); |
| 5662 if (FLAG_throw_on_javascript_int_overflow) { |
| 5663 summary->set_temp(0, Location::RequiresRegister()); |
| 5664 summary->set_temp(1, Location::RequiresRegister()); |
| 5665 } |
| 5666 return summary; |
5234 } | 5667 } |
5235 | 5668 |
5236 | 5669 |
5237 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5670 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5238 UNIMPLEMENTED(); | 5671 ASSERT(op_kind() == Token::kBIT_NOT); |
5239 } | 5672 QRegister value = locs()->in(0).fpu_reg(); |
5240 | 5673 QRegister out = locs()->out(0).fpu_reg(); |
5241 | 5674 Label* deopt = NULL; |
| 5675 if (FLAG_throw_on_javascript_int_overflow) { |
| 5676 deopt = compiler->AddDeoptStub(deopt_id(), |
| 5677 kDeoptUnaryMintOp); |
| 5678 } |
| 5679 __ vmvnq(out, value); |
| 5680 if (FLAG_throw_on_javascript_int_overflow) { |
| 5681 Register tmp1 = locs()->temp(0).reg(); |
| 5682 Register tmp2 = locs()->temp(1).reg(); |
| 5683 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); |
| 5684 } |
| 5685 } |
| 5686 |
| 5687 |
5242 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { | 5688 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { |
5243 return new LocationSummary(0, 0, LocationSummary::kCall); | 5689 return new LocationSummary(0, 0, LocationSummary::kCall); |
5244 } | 5690 } |
5245 | 5691 |
5246 | 5692 |
5247 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5693 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5248 compiler->GenerateRuntimeCall(token_pos(), | 5694 compiler->GenerateRuntimeCall(token_pos(), |
5249 deopt_id(), | 5695 deopt_id(), |
5250 kThrowRuntimeEntry, | 5696 kThrowRuntimeEntry, |
5251 1, | 5697 1, |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5437 compiler->GenerateCall(token_pos(), | 5883 compiler->GenerateCall(token_pos(), |
5438 &label, | 5884 &label, |
5439 PcDescriptors::kOther, | 5885 PcDescriptors::kOther, |
5440 locs()); | 5886 locs()); |
5441 __ Drop(ArgumentCount()); // Discard arguments. | 5887 __ Drop(ArgumentCount()); // Discard arguments. |
5442 } | 5888 } |
5443 | 5889 |
5444 } // namespace dart | 5890 } // namespace dart |
5445 | 5891 |
5446 #endif // defined TARGET_ARCH_ARM | 5892 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |