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 |