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/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 default: | 373 default: |
374 UNREACHABLE(); | 374 UNREACHABLE(); |
375 return VS; | 375 return VS; |
376 } | 376 } |
377 } | 377 } |
378 | 378 |
379 | 379 |
380 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { | 380 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { |
381 const intptr_t kNumInputs = 2; | 381 const intptr_t kNumInputs = 2; |
382 if (operation_cid() == kMintCid) { | 382 if (operation_cid() == kMintCid) { |
383 const intptr_t kNumTemps = 3; | 383 const intptr_t kNumTemps = 0; |
384 LocationSummary* locs = | 384 LocationSummary* locs = |
385 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 385 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
386 locs->set_in(0, Location::RequiresFpuRegister()); | 386 locs->set_in(0, Location::Pair(Location::RequiresRegister(), |
387 locs->set_in(1, Location::RequiresFpuRegister()); | 387 Location::RequiresRegister())); |
388 locs->set_temp(0, Location::RequiresFpuRegister()); | 388 locs->set_in(1, Location::Pair(Location::RequiresRegister(), |
389 locs->set_temp(1, Location::RequiresRegister()); | 389 Location::RequiresRegister())); |
390 locs->set_temp(2, Location::RequiresRegister()); | |
391 locs->set_out(0, Location::RequiresRegister()); | 390 locs->set_out(0, Location::RequiresRegister()); |
392 return locs; | 391 return locs; |
393 } | 392 } |
394 if (operation_cid() == kDoubleCid) { | 393 if (operation_cid() == kDoubleCid) { |
395 const intptr_t kNumTemps = 0; | 394 const intptr_t kNumTemps = 0; |
396 LocationSummary* locs = | 395 LocationSummary* locs = |
397 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 396 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
398 locs->set_in(0, Location::RequiresFpuRegister()); | 397 locs->set_in(0, Location::RequiresFpuRegister()); |
399 locs->set_in(1, Location::RequiresFpuRegister()); | 398 locs->set_in(1, Location::RequiresFpuRegister()); |
400 locs->set_out(0, Location::RequiresRegister()); | 399 locs->set_out(0, Location::RequiresRegister()); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 UNREACHABLE(); | 507 UNREACHABLE(); |
509 return VS; | 508 return VS; |
510 } | 509 } |
511 } | 510 } |
512 | 511 |
513 | 512 |
514 static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | 513 static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
515 LocationSummary* locs, | 514 LocationSummary* locs, |
516 Token::Kind kind) { | 515 Token::Kind kind) { |
517 ASSERT(Token::IsEqualityOperator(kind)); | 516 ASSERT(Token::IsEqualityOperator(kind)); |
518 const QRegister left = locs->in(0).fpu_reg(); | 517 PairLocation* left_pair = locs->in(0).AsPairLocation(); |
519 const QRegister right = locs->in(1).fpu_reg(); | 518 Register left1 = left_pair->At(0).reg(); |
520 const QRegister tmpq = locs->temp(0).fpu_reg(); | 519 Register left2 = left_pair->At(1).reg(); |
521 const Register tmp_lo = locs->temp(1).reg(); | 520 PairLocation* right_pair = locs->in(1).AsPairLocation(); |
522 const Register tmp_hi = locs->temp(2).reg(); | 521 Register right1 = right_pair->At(0).reg(); |
| 522 Register right2 = right_pair->At(1).reg(); |
523 | 523 |
524 __ vceqqi(kWord, tmpq, left, right); | 524 // Compare lower. |
525 __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(tmpq)); | 525 __ cmp(left1, ShifterOperand(right1)); |
526 // tmp_lo and tmp_hi must both be 0xffffffff. | 526 // Compare upper if lower is equal. |
527 __ and_(tmp_lo, tmp_lo, ShifterOperand(tmp_hi)); | 527 __ cmp(left2, ShifterOperand(right2), EQ); |
528 | 528 return TokenKindToMintCondition(kind); |
529 Condition true_condition = TokenKindToMintCondition(kind); | |
530 __ CompareImmediate(tmp_lo, 0xffffffff); | |
531 return true_condition; | |
532 } | 529 } |
533 | 530 |
534 | 531 |
535 static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, | 532 static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
536 LocationSummary* locs, | 533 LocationSummary* locs, |
537 Token::Kind kind) { | 534 Token::Kind kind) { |
538 const QRegister left = locs->in(0).fpu_reg(); | 535 PairLocation* left_pair = locs->in(0).AsPairLocation(); |
539 const QRegister right = locs->in(1).fpu_reg(); | 536 Register left1 = left_pair->At(0).reg(); |
540 const DRegister dleft0 = EvenDRegisterOf(left); | 537 Register left2 = left_pair->At(1).reg(); |
541 const DRegister dright0 = EvenDRegisterOf(right); | 538 PairLocation* right_pair = locs->in(1).AsPairLocation(); |
542 const SRegister sleft0 = EvenSRegisterOf(dleft0); | 539 Register right1 = right_pair->At(0).reg(); |
543 const SRegister sleft1 = OddSRegisterOf(dleft0); | 540 Register right2 = right_pair->At(1).reg(); |
544 const SRegister sright0 = EvenSRegisterOf(dright0); | |
545 const SRegister sright1 = OddSRegisterOf(dright0); | |
546 | 541 |
547 const Register tmp_left = locs->temp(0).reg(); | 542 Register out = locs->temp(0).reg(); |
548 const Register tmp_right = locs->temp(1).reg(); | |
549 | 543 |
550 // 64-bit comparison | 544 // 64-bit comparison |
551 Condition hi_true_cond, hi_false_cond, lo_false_cond; | 545 Condition hi_true_cond, hi_false_cond, lo_false_cond; |
552 switch (kind) { | 546 switch (kind) { |
553 case Token::kLT: | 547 case Token::kLT: |
554 case Token::kLTE: | 548 case Token::kLTE: |
555 hi_true_cond = LT; | 549 hi_true_cond = LT; |
556 hi_false_cond = GT; | 550 hi_false_cond = GT; |
557 lo_false_cond = (kind == Token::kLT) ? CS : HI; | 551 lo_false_cond = (kind == Token::kLT) ? CS : HI; |
558 break; | 552 break; |
559 case Token::kGT: | 553 case Token::kGT: |
560 case Token::kGTE: | 554 case Token::kGTE: |
561 hi_true_cond = GT; | 555 hi_true_cond = GT; |
562 hi_false_cond = LT; | 556 hi_false_cond = LT; |
563 lo_false_cond = (kind == Token::kGT) ? LS : CC; | 557 lo_false_cond = (kind == Token::kGT) ? LS : CC; |
564 break; | 558 break; |
565 default: | 559 default: |
566 UNREACHABLE(); | 560 UNREACHABLE(); |
567 hi_true_cond = hi_false_cond = lo_false_cond = VS; | 561 hi_true_cond = hi_false_cond = lo_false_cond = VS; |
568 } | 562 } |
569 | 563 |
570 Label is_true, is_false, done; | 564 Label is_true, is_false, done; |
571 __ vmovrs(tmp_left, sleft1); | 565 // Compare upper halves first. |
572 __ vmovrs(tmp_right, sright1); | 566 __ cmp(left2, ShifterOperand(right2)); |
573 __ cmp(tmp_left, ShifterOperand(tmp_right)); | 567 __ LoadImmediate(out, 0, hi_false_cond); |
574 __ b(&is_false, hi_false_cond); | 568 __ LoadImmediate(out, 1, hi_true_cond); |
575 __ b(&is_true, hi_true_cond); | 569 // If higher words aren't equal, skip comparing lower words. |
| 570 __ b(&done, NE); |
576 | 571 |
577 __ vmovrs(tmp_left, sleft0); | 572 __ cmp(left1, ShifterOperand(right1)); |
578 __ vmovrs(tmp_right, sright0); | 573 __ LoadImmediate(out, 1); |
579 __ cmp(tmp_left, ShifterOperand(tmp_right)); | 574 __ LoadImmediate(out, 0, lo_false_cond); |
580 __ b(&is_false, lo_false_cond); | 575 __ Bind(&done); |
581 // Else is true. | |
582 __ b(&is_true); | |
583 | 576 |
584 __ Bind(&is_false); | |
585 __ LoadImmediate(tmp_left, 0); | |
586 __ b(&done); | |
587 __ Bind(&is_true); | |
588 __ LoadImmediate(tmp_left, 1); | |
589 __ Bind(&done); | |
590 return NegateCondition(lo_false_cond); | 577 return NegateCondition(lo_false_cond); |
591 } | 578 } |
592 | 579 |
593 | 580 |
594 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 581 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
595 switch (kind) { | 582 switch (kind) { |
596 case Token::kEQ: return EQ; | 583 case Token::kEQ: return EQ; |
597 case Token::kNE: return NE; | 584 case Token::kNE: return NE; |
598 case Token::kLT: return LT; | 585 case Token::kLT: return LT; |
599 case Token::kGT: return GT; | 586 case Token::kGT: return GT; |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 __ Bind(&is_true); | 773 __ Bind(&is_true); |
787 __ LoadObject(result_reg, Bool::True()); | 774 __ LoadObject(result_reg, Bool::True()); |
788 __ Bind(&done); | 775 __ Bind(&done); |
789 } | 776 } |
790 | 777 |
791 | 778 |
792 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { | 779 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { |
793 const intptr_t kNumInputs = 2; | 780 const intptr_t kNumInputs = 2; |
794 const intptr_t kNumTemps = 0; | 781 const intptr_t kNumTemps = 0; |
795 if (operation_cid() == kMintCid) { | 782 if (operation_cid() == kMintCid) { |
796 const intptr_t kNumTemps = 2; | 783 const intptr_t kNumTemps = 1; |
797 LocationSummary* locs = | 784 LocationSummary* locs = |
798 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 785 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
799 locs->set_in(0, Location::RequiresFpuRegister()); | 786 locs->set_in(0, Location::Pair(Location::RequiresRegister(), |
800 locs->set_in(1, Location::RequiresFpuRegister()); | 787 Location::RequiresRegister())); |
| 788 locs->set_in(1, Location::Pair(Location::RequiresRegister(), |
| 789 Location::RequiresRegister())); |
801 locs->set_temp(0, Location::RequiresRegister()); | 790 locs->set_temp(0, Location::RequiresRegister()); |
802 locs->set_temp(1, Location::RequiresRegister()); | |
803 locs->set_out(0, Location::RequiresRegister()); | 791 locs->set_out(0, Location::RequiresRegister()); |
804 return locs; | 792 return locs; |
805 } | 793 } |
806 if (operation_cid() == kDoubleCid) { | 794 if (operation_cid() == kDoubleCid) { |
807 LocationSummary* summary = | 795 LocationSummary* summary = |
808 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 796 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
809 summary->set_in(0, Location::RequiresFpuRegister()); | 797 summary->set_in(0, Location::RequiresFpuRegister()); |
810 summary->set_in(1, Location::RequiresFpuRegister()); | 798 summary->set_in(1, Location::RequiresFpuRegister()); |
811 summary->set_out(0, Location::RequiresRegister()); | 799 summary->set_out(0, Location::RequiresRegister()); |
812 return summary; | 800 return summary; |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 (representation() == kUnboxedInt32x4) || | 1134 (representation() == kUnboxedInt32x4) || |
1147 (representation() == kUnboxedFloat64x2)) { | 1135 (representation() == kUnboxedFloat64x2)) { |
1148 if (class_id() == kTypedDataFloat32ArrayCid) { | 1136 if (class_id() == kTypedDataFloat32ArrayCid) { |
1149 // Need register <= Q7 for float operations. | 1137 // Need register <= Q7 for float operations. |
1150 // TODO(fschneider): Add a register policy to specify a subset of | 1138 // TODO(fschneider): Add a register policy to specify a subset of |
1151 // registers. | 1139 // registers. |
1152 locs->set_out(0, Location::FpuRegisterLocation(Q7)); | 1140 locs->set_out(0, Location::FpuRegisterLocation(Q7)); |
1153 } else { | 1141 } else { |
1154 locs->set_out(0, Location::RequiresFpuRegister()); | 1142 locs->set_out(0, Location::RequiresFpuRegister()); |
1155 } | 1143 } |
| 1144 } else if (representation() == kUnboxedMint) { |
| 1145 locs->set_out(0, Location::Pair(Location::RequiresRegister(), |
| 1146 Location::RequiresRegister())); |
1156 } else { | 1147 } else { |
| 1148 ASSERT(representation() == kTagged); |
1157 locs->set_out(0, Location::RequiresRegister()); | 1149 locs->set_out(0, Location::RequiresRegister()); |
1158 } | 1150 } |
1159 return locs; | 1151 return locs; |
1160 } | 1152 } |
1161 | 1153 |
1162 | 1154 |
1163 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1155 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
1164 if ((representation() == kUnboxedDouble) || | 1156 if ((representation() == kUnboxedDouble) || |
1165 (representation() == kUnboxedMint) || | |
1166 (representation() == kUnboxedFloat32x4) || | 1157 (representation() == kUnboxedFloat32x4) || |
1167 (representation() == kUnboxedInt32x4) || | 1158 (representation() == kUnboxedInt32x4) || |
1168 (representation() == kUnboxedFloat64x2)) { | 1159 (representation() == kUnboxedFloat64x2)) { |
1169 const Register array = locs()->in(0).reg(); | 1160 const Register array = locs()->in(0).reg(); |
1170 const Register idx = locs()->in(1).reg(); | 1161 const Register idx = locs()->in(1).reg(); |
1171 switch (index_scale()) { | 1162 switch (index_scale()) { |
1172 case 1: | 1163 case 1: |
1173 __ add(idx, array, ShifterOperand(idx, ASR, kSmiTagSize)); | 1164 __ add(idx, array, ShifterOperand(idx, ASR, kSmiTagSize)); |
1174 break; | 1165 break; |
1175 case 4: | 1166 case 4: |
(...skipping 11 matching lines...) Expand all Loading... |
1187 } | 1178 } |
1188 if (!IsExternal()) { | 1179 if (!IsExternal()) { |
1189 ASSERT(this->array()->definition()->representation() == kTagged); | 1180 ASSERT(this->array()->definition()->representation() == kTagged); |
1190 __ AddImmediate(idx, | 1181 __ AddImmediate(idx, |
1191 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag); | 1182 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag); |
1192 } | 1183 } |
1193 Address element_address(idx); | 1184 Address element_address(idx); |
1194 const QRegister result = locs()->out(0).fpu_reg(); | 1185 const QRegister result = locs()->out(0).fpu_reg(); |
1195 const DRegister dresult0 = EvenDRegisterOf(result); | 1186 const DRegister dresult0 = EvenDRegisterOf(result); |
1196 switch (class_id()) { | 1187 switch (class_id()) { |
1197 case kTypedDataInt32ArrayCid: | |
1198 __ veorq(result, result, result); | |
1199 __ ldr(TMP, element_address); | |
1200 // Re-use the index register so we don't have to require a low-numbered | |
1201 // Q register. | |
1202 // Sign-extend into idx. | |
1203 __ Asr(idx, TMP, 31); | |
1204 __ vmovdrr(dresult0, TMP, idx); | |
1205 break; | |
1206 case kTypedDataUint32ArrayCid: | |
1207 __ veorq(result, result, result); | |
1208 __ ldr(TMP, element_address); | |
1209 // Re-use the index register so we don't have to require a low-numbered | |
1210 // Q register. | |
1211 __ LoadImmediate(idx, 0); | |
1212 __ vmovdrr(dresult0, TMP, idx); | |
1213 break; | |
1214 case kTypedDataFloat32ArrayCid: | 1188 case kTypedDataFloat32ArrayCid: |
1215 // Load single precision float. | 1189 // Load single precision float. |
1216 // vldrs does not support indexed addressing. | 1190 // vldrs does not support indexed addressing. |
1217 __ vldrs(EvenSRegisterOf(dresult0), element_address); | 1191 __ vldrs(EvenSRegisterOf(dresult0), element_address); |
1218 break; | 1192 break; |
1219 case kTypedDataFloat64ArrayCid: | 1193 case kTypedDataFloat64ArrayCid: |
1220 // vldrd does not support indexed addressing. | 1194 // vldrd does not support indexed addressing. |
1221 __ vldrd(dresult0, element_address); | 1195 __ vldrd(dresult0, element_address); |
1222 break; | 1196 break; |
1223 case kTypedDataFloat64x2ArrayCid: | 1197 case kTypedDataFloat64x2ArrayCid: |
1224 case kTypedDataInt32x4ArrayCid: | 1198 case kTypedDataInt32x4ArrayCid: |
1225 case kTypedDataFloat32x4ArrayCid: | 1199 case kTypedDataFloat32x4ArrayCid: |
1226 __ vldmd(IA, idx, dresult0, 2); | 1200 __ vldmd(IA, idx, dresult0, 2); |
1227 break; | 1201 break; |
| 1202 default: |
| 1203 UNREACHABLE(); |
1228 } | 1204 } |
1229 return; | 1205 return; |
1230 } | 1206 } |
1231 | 1207 |
1232 const Register array = locs()->in(0).reg(); | 1208 const Register array = locs()->in(0).reg(); |
1233 Location index = locs()->in(1); | 1209 Location index = locs()->in(1); |
1234 ASSERT(index.IsRegister()); // TODO(regis): Revisit. | 1210 ASSERT(index.IsRegister()); // TODO(regis): Revisit. |
1235 Address element_address(kNoRegister, 0); | 1211 Address element_address(kNoRegister, 0); |
1236 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays | 1212 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays |
1237 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the | 1213 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the |
(...skipping 22 matching lines...) Expand all Loading... |
1260 case 4: { | 1236 case 4: { |
1261 __ add(index.reg(), array, ShifterOperand(index.reg(), LSL, 1)); | 1237 __ add(index.reg(), array, ShifterOperand(index.reg(), LSL, 1)); |
1262 element_address = Address(index.reg(), offset); | 1238 element_address = Address(index.reg(), offset); |
1263 break; | 1239 break; |
1264 } | 1240 } |
1265 // Cases 8 and 16 are only for unboxed values and are handled above. | 1241 // Cases 8 and 16 are only for unboxed values and are handled above. |
1266 default: | 1242 default: |
1267 UNREACHABLE(); | 1243 UNREACHABLE(); |
1268 } | 1244 } |
1269 | 1245 |
1270 const Register result = locs()->out(0).reg(); | 1246 if (representation() == kUnboxedMint) { |
| 1247 ASSERT(locs()->out(0).IsPairLocation()); |
| 1248 PairLocation* result_pair = locs()->out(0).AsPairLocation(); |
| 1249 Register result1 = result_pair->At(0).reg(); |
| 1250 Register result2 = result_pair->At(1).reg(); |
| 1251 switch (class_id()) { |
| 1252 case kTypedDataInt32ArrayCid: |
| 1253 // Load low word. |
| 1254 __ ldr(result1, element_address); |
| 1255 // Sign extend into high word. |
| 1256 __ SignFill(result2, result1); |
| 1257 break; |
| 1258 case kTypedDataUint32ArrayCid: |
| 1259 // Load low word. |
| 1260 __ ldr(result1, element_address); |
| 1261 // Zero high word. |
| 1262 __ eor(result2, result2, ShifterOperand(result2)); |
| 1263 break; |
| 1264 default: |
| 1265 UNREACHABLE(); |
| 1266 break; |
| 1267 } |
| 1268 return; |
| 1269 } |
| 1270 |
| 1271 ASSERT(representation() == kTagged); |
| 1272 |
| 1273 Register result = locs()->out(0).reg(); |
1271 switch (class_id()) { | 1274 switch (class_id()) { |
1272 case kTypedDataInt8ArrayCid: | 1275 case kTypedDataInt8ArrayCid: |
1273 ASSERT(index_scale() == 1); | 1276 ASSERT(index_scale() == 1); |
1274 __ ldrsb(result, element_address); | 1277 __ ldrsb(result, element_address); |
1275 __ SmiTag(result); | 1278 __ SmiTag(result); |
1276 break; | 1279 break; |
1277 case kTypedDataUint8ArrayCid: | 1280 case kTypedDataUint8ArrayCid: |
1278 case kTypedDataUint8ClampedArrayCid: | 1281 case kTypedDataUint8ClampedArrayCid: |
1279 case kExternalTypedDataUint8ArrayCid: | 1282 case kExternalTypedDataUint8ArrayCid: |
1280 case kExternalTypedDataUint8ClampedArrayCid: | 1283 case kExternalTypedDataUint8ClampedArrayCid: |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1377 case kTypedDataInt8ArrayCid: | 1380 case kTypedDataInt8ArrayCid: |
1378 case kTypedDataUint8ArrayCid: | 1381 case kTypedDataUint8ArrayCid: |
1379 case kTypedDataUint8ClampedArrayCid: | 1382 case kTypedDataUint8ClampedArrayCid: |
1380 case kOneByteStringCid: | 1383 case kOneByteStringCid: |
1381 case kTypedDataInt16ArrayCid: | 1384 case kTypedDataInt16ArrayCid: |
1382 case kTypedDataUint16ArrayCid: | 1385 case kTypedDataUint16ArrayCid: |
1383 locs->set_in(2, Location::WritableRegister()); | 1386 locs->set_in(2, Location::WritableRegister()); |
1384 break; | 1387 break; |
1385 case kTypedDataInt32ArrayCid: | 1388 case kTypedDataInt32ArrayCid: |
1386 case kTypedDataUint32ArrayCid: | 1389 case kTypedDataUint32ArrayCid: |
1387 // Mints are stored in Q registers. For smis, use a writable register | 1390 // For smis, use a writable register because the value must be untagged |
1388 // because the value must be untagged before storing. | 1391 // before storing. Mints are stored in register pairs. |
1389 locs->set_in(2, value()->IsSmiValue() | 1392 if (value()->IsSmiValue()) { |
1390 ? Location::WritableRegister() | 1393 locs->set_in(2, Location::WritableRegister()); |
1391 : Location::FpuRegisterLocation(Q7)); | 1394 } else { |
| 1395 // We only move the lower 32-bits so we don't care where the high bits |
| 1396 // are located. |
| 1397 locs->set_in(2, Location::Pair(Location::RequiresRegister(), |
| 1398 Location::Any())); |
| 1399 } |
1392 break; | 1400 break; |
1393 case kTypedDataFloat32ArrayCid: | 1401 case kTypedDataFloat32ArrayCid: |
1394 // Need low register (<= Q7). | 1402 // Need low register (<= Q7). |
1395 locs->set_in(2, Location::FpuRegisterLocation(Q7)); | 1403 locs->set_in(2, Location::FpuRegisterLocation(Q7)); |
1396 break; | 1404 break; |
1397 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. | 1405 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. |
1398 case kTypedDataInt32x4ArrayCid: | 1406 case kTypedDataInt32x4ArrayCid: |
1399 case kTypedDataFloat32x4ArrayCid: | 1407 case kTypedDataFloat32x4ArrayCid: |
1400 case kTypedDataFloat64x2ArrayCid: | 1408 case kTypedDataFloat64x2ArrayCid: |
1401 locs->set_in(2, Location::RequiresFpuRegister()); | 1409 locs->set_in(2, Location::RequiresFpuRegister()); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1566 } | 1574 } |
1567 case kTypedDataInt32ArrayCid: | 1575 case kTypedDataInt32ArrayCid: |
1568 case kTypedDataUint32ArrayCid: { | 1576 case kTypedDataUint32ArrayCid: { |
1569 if (value()->IsSmiValue()) { | 1577 if (value()->IsSmiValue()) { |
1570 ASSERT(RequiredInputRepresentation(2) == kTagged); | 1578 ASSERT(RequiredInputRepresentation(2) == kTagged); |
1571 const Register value = locs()->in(2).reg(); | 1579 const Register value = locs()->in(2).reg(); |
1572 __ SmiUntag(value); | 1580 __ SmiUntag(value); |
1573 __ str(value, element_address); | 1581 __ str(value, element_address); |
1574 } else { | 1582 } else { |
1575 ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); | 1583 ASSERT(RequiredInputRepresentation(2) == kUnboxedMint); |
1576 const QRegister value = locs()->in(2).fpu_reg(); | 1584 PairLocation* value_pair = locs()->in(2).AsPairLocation(); |
1577 ASSERT(value == Q7); | 1585 Register value1 = value_pair->At(0).reg(); |
1578 __ vmovrs(TMP, EvenSRegisterOf(EvenDRegisterOf(value))); | 1586 __ str(value1, element_address); |
1579 __ str(TMP, element_address); | |
1580 } | 1587 } |
1581 break; | 1588 break; |
1582 } | 1589 } |
1583 default: | 1590 default: |
1584 UNREACHABLE(); | 1591 UNREACHABLE(); |
1585 } | 1592 } |
1586 } | 1593 } |
1587 | 1594 |
1588 | 1595 |
1589 LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const { | 1596 LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const { |
(...skipping 4129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5719 const Register length = length_loc.reg(); | 5726 const Register length = length_loc.reg(); |
5720 const Register index = index_loc.reg(); | 5727 const Register index = index_loc.reg(); |
5721 __ cmp(index, ShifterOperand(length)); | 5728 __ cmp(index, ShifterOperand(length)); |
5722 __ b(deopt, CS); | 5729 __ b(deopt, CS); |
5723 } | 5730 } |
5724 } | 5731 } |
5725 | 5732 |
5726 | 5733 |
5727 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, | 5734 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
5728 Label* overflow, | 5735 Label* overflow, |
5729 QRegister result, | 5736 Register result_lo, |
5730 Register tmp_hi, Register tmp_lo) { | 5737 Register result_hi) { |
5731 __ vmovrrd(tmp_lo, tmp_hi, EvenDRegisterOf(result)); | |
5732 // Compare upper half. | 5738 // Compare upper half. |
5733 Label check_lower; | 5739 Label check_lower; |
5734 __ CompareImmediate(tmp_hi, 0x00200000); | 5740 __ CompareImmediate(result_hi, 0x00200000); |
5735 __ b(overflow, GT); | 5741 __ b(overflow, GT); |
5736 __ b(&check_lower, NE); | 5742 __ b(&check_lower, NE); |
5737 | 5743 |
5738 __ CompareImmediate(tmp_lo, 0); | 5744 __ CompareImmediate(result_lo, 0); |
5739 __ b(overflow, HI); | 5745 __ b(overflow, HI); |
5740 | 5746 |
5741 __ Bind(&check_lower); | 5747 __ Bind(&check_lower); |
5742 __ CompareImmediate(tmp_hi, -0x00200000); | 5748 __ CompareImmediate(result_hi, -0x00200000); |
5743 __ b(overflow, LT); | 5749 __ b(overflow, LT); |
5744 // Anything in the lower part would make the number bigger than the lower | 5750 // Anything in the lower part would make the number bigger than the lower |
5745 // bound, so we are done. | 5751 // bound, so we are done. |
5746 } | 5752 } |
5747 | 5753 |
5748 | 5754 |
5749 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { | 5755 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
5750 const intptr_t kNumInputs = 1; | 5756 const intptr_t kNumInputs = 1; |
5751 const intptr_t value_cid = value()->Type()->ToCid(); | 5757 const intptr_t kNumTemps = 1; |
5752 const bool needs_writable_input = (value_cid != kMintCid); | |
5753 const bool needs_temp = (value_cid != kMintCid); | |
5754 const intptr_t kNumTemps = needs_temp ? 1 : 0; | |
5755 LocationSummary* summary = | 5758 LocationSummary* summary = |
5756 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 5759 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
5757 summary->set_in(0, needs_writable_input | 5760 summary->set_in(0, Location::RequiresRegister()); |
5758 ? Location::WritableRegister() | 5761 summary->set_temp(0, Location::RequiresRegister()); |
5759 : Location::RequiresRegister()); | 5762 summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
5760 if (needs_temp) { | 5763 Location::RequiresRegister())); |
5761 summary->set_temp(0, Location::RequiresRegister()); | |
5762 } | |
5763 summary->set_out(0, Location::RequiresFpuRegister()); | |
5764 return summary; | 5764 return summary; |
5765 } | 5765 } |
5766 | 5766 |
5767 | 5767 |
5768 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5768 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5769 const intptr_t value_cid = value()->Type()->ToCid(); | 5769 const intptr_t value_cid = value()->Type()->ToCid(); |
5770 const Register value = locs()->in(0).reg(); | 5770 const Register value = locs()->in(0).reg(); |
5771 const QRegister result = locs()->out(0).fpu_reg(); | 5771 PairLocation* result_pair = locs()->out(0).AsPairLocation(); |
| 5772 Register result_lo = result_pair->At(0).reg(); |
| 5773 Register result_hi = result_pair->At(1).reg(); |
| 5774 ASSERT(value != result_lo); |
| 5775 ASSERT(value != result_hi); |
5772 | 5776 |
5773 __ Comment("UnboxIntegerInstr"); | 5777 __ Comment("UnboxIntegerInstr"); |
5774 __ veorq(result, result, result); | |
5775 if (value_cid == kMintCid) { | 5778 if (value_cid == kMintCid) { |
5776 __ LoadDFromOffset(EvenDRegisterOf(result), value, | 5779 // Load low word. |
5777 Mint::value_offset() - kHeapObjectTag); | 5780 __ LoadFromOffset(kWord, |
| 5781 result_lo, |
| 5782 value, |
| 5783 Mint::value_offset() - kHeapObjectTag); |
| 5784 // Load high word. |
| 5785 __ LoadFromOffset(kWord, |
| 5786 result_hi, |
| 5787 value, |
| 5788 Mint::value_offset() - kHeapObjectTag + kWordSize); |
5778 } else if (value_cid == kSmiCid) { | 5789 } else if (value_cid == kSmiCid) { |
5779 const Register temp = locs()->temp(0).reg(); | 5790 // Load Smi into result_lo. |
5780 __ SmiUntag(value); | 5791 __ mov(result_lo, ShifterOperand(value)); |
5781 // Sign extend value into temp. | 5792 // Untag. |
5782 __ Asr(temp, value, 31); | 5793 __ SmiUntag(result_lo); |
5783 __ vmovdrr(EvenDRegisterOf(result), value, temp); | 5794 __ SignFill(result_hi, result_lo); |
5784 } else { | 5795 } else { |
5785 const Register temp = locs()->temp(0).reg(); | 5796 const Register temp = locs()->temp(0).reg(); |
5786 Label* deopt = compiler->AddDeoptStub(deopt_id_, | 5797 Label* deopt = compiler->AddDeoptStub(deopt_id_, |
5787 ICData::kDeoptUnboxInteger); | 5798 ICData::kDeoptUnboxInteger); |
5788 Label is_smi, done; | 5799 Label is_smi, done; |
5789 __ tst(value, ShifterOperand(kSmiTagMask)); | 5800 __ tst(value, ShifterOperand(kSmiTagMask)); |
5790 __ b(&is_smi, EQ); | 5801 __ b(&is_smi, EQ); |
5791 __ CompareClassId(value, kMintCid, temp); | 5802 __ CompareClassId(value, kMintCid, temp); |
5792 __ b(deopt, NE); | 5803 __ b(deopt, NE); |
5793 | 5804 |
5794 // It's a Mint. | 5805 // It's a Mint. |
5795 __ LoadDFromOffset(EvenDRegisterOf(result), value, | 5806 // Load low word. |
5796 Mint::value_offset() - kHeapObjectTag); | 5807 __ LoadFromOffset(kWord, |
| 5808 result_lo, |
| 5809 value, |
| 5810 Mint::value_offset() - kHeapObjectTag); |
| 5811 // Load high word. |
| 5812 __ LoadFromOffset(kWord, |
| 5813 result_hi, |
| 5814 value, |
| 5815 Mint::value_offset() - kHeapObjectTag + kWordSize); |
5797 __ b(&done); | 5816 __ b(&done); |
5798 | 5817 |
5799 // It's a Smi. | 5818 // It's a Smi. |
5800 __ Bind(&is_smi); | 5819 __ Bind(&is_smi); |
5801 __ SmiUntag(value); | 5820 // Load Smi into result_lo. |
5802 // Sign extend into temp. | 5821 __ mov(result_lo, ShifterOperand(value)); |
5803 __ Asr(temp, value, 31); | 5822 // Untag. |
5804 __ vmovdrr(EvenDRegisterOf(result), value, temp); | 5823 __ SmiUntag(result_lo); |
| 5824 // Sign extend result_lo into result_hi. |
| 5825 __ SignFill(result_hi, result_lo); |
5805 __ Bind(&done); | 5826 __ Bind(&done); |
5806 } | 5827 } |
5807 } | 5828 } |
5808 | 5829 |
5809 | 5830 |
5810 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { | 5831 LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const { |
5811 const intptr_t kNumInputs = 1; | 5832 const intptr_t kNumInputs = 1; |
5812 const intptr_t kNumTemps = 2; | 5833 const intptr_t kNumTemps = 1; |
5813 LocationSummary* summary = | 5834 LocationSummary* summary = |
5814 new LocationSummary(kNumInputs, | 5835 new LocationSummary(kNumInputs, |
5815 kNumTemps, | 5836 kNumTemps, |
5816 LocationSummary::kCallOnSlowPath); | 5837 LocationSummary::kCallOnSlowPath); |
5817 summary->set_in(0, Location::RequiresFpuRegister()); | 5838 summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| 5839 Location::RequiresRegister())); |
5818 summary->set_temp(0, Location::RequiresRegister()); | 5840 summary->set_temp(0, Location::RequiresRegister()); |
5819 summary->set_temp(1, Location::RequiresRegister()); | |
5820 summary->set_out(0, Location::RequiresRegister()); | 5841 summary->set_out(0, Location::RequiresRegister()); |
5821 return summary; | 5842 return summary; |
5822 } | 5843 } |
5823 | 5844 |
5824 | 5845 |
5825 class BoxIntegerSlowPath : public SlowPathCode { | 5846 class BoxIntegerSlowPath : public SlowPathCode { |
5826 public: | 5847 public: |
5827 explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) | 5848 explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) |
5828 : instruction_(instruction) { } | 5849 : instruction_(instruction) { } |
5829 | 5850 |
(...skipping 21 matching lines...) Expand all Loading... |
5851 } | 5872 } |
5852 | 5873 |
5853 private: | 5874 private: |
5854 BoxIntegerInstr* instruction_; | 5875 BoxIntegerInstr* instruction_; |
5855 }; | 5876 }; |
5856 | 5877 |
5857 | 5878 |
5858 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5879 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5859 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); | 5880 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
5860 compiler->AddSlowPathCode(slow_path); | 5881 compiler->AddSlowPathCode(slow_path); |
5861 | 5882 PairLocation* value_pair = locs()->in(0).AsPairLocation(); |
5862 const Register out_reg = locs()->out(0).reg(); | 5883 Register value_lo = value_pair->At(0).reg(); |
5863 const QRegister value = locs()->in(0).fpu_reg(); | 5884 Register value_hi = value_pair->At(1).reg(); |
5864 const DRegister dvalue0 = EvenDRegisterOf(value); | 5885 Register tmp = locs()->temp(0).reg(); |
5865 const Register lo = locs()->temp(0).reg(); | 5886 Register out_reg = locs()->out(0).reg(); |
5866 const Register hi = locs()->temp(1).reg(); | |
5867 | 5887 |
5868 // Unboxed operations produce smis or mint-sized values. | 5888 // Unboxed operations produce smis or mint-sized values. |
5869 // Check if value fits into a smi. | 5889 // Check if value fits into a smi. |
5870 __ Comment("BoxIntegerInstr"); | 5890 __ Comment("BoxIntegerInstr"); |
5871 Label not_smi, done, maybe_pos_smi, maybe_neg_smi, is_smi; | 5891 Label not_smi, done, maybe_pos_smi, maybe_neg_smi, is_smi; |
5872 __ vmovrrd(lo, hi, dvalue0); | 5892 // Check high word. |
5873 __ CompareImmediate(hi, 0); | 5893 __ CompareImmediate(value_hi, 0); |
5874 __ b(&maybe_pos_smi, EQ); | 5894 __ b(&maybe_pos_smi, EQ); |
5875 | 5895 |
5876 __ CompareImmediate(hi, -1); | 5896 __ CompareImmediate(value_hi, -1); |
5877 __ b(&maybe_neg_smi, EQ); | 5897 __ b(&maybe_neg_smi, EQ); |
5878 __ b(¬_smi); | 5898 __ b(¬_smi); |
5879 | 5899 |
5880 __ Bind(&maybe_pos_smi); | 5900 __ Bind(&maybe_pos_smi); |
5881 __ CompareImmediate(lo, kSmiMax); | 5901 __ CompareImmediate(value_lo, kSmiMax); |
5882 __ b(&is_smi, LS); // unsigned lower or same. | 5902 __ b(&is_smi, LS); // unsigned lower or same. |
5883 __ b(¬_smi); | 5903 __ b(¬_smi); |
5884 | 5904 |
5885 __ Bind(&maybe_neg_smi); | 5905 __ Bind(&maybe_neg_smi); |
5886 __ CompareImmediate(lo, 0); | 5906 __ CompareImmediate(value_lo, 0); |
5887 __ b(¬_smi, GE); | 5907 __ b(¬_smi, GE); |
5888 __ CompareImmediate(lo, kSmiMin); | 5908 __ CompareImmediate(value_lo, kSmiMin); |
5889 __ b(¬_smi, LT); | 5909 __ b(¬_smi, LT); |
5890 | 5910 |
5891 // lo is a Smi. Tag it and return. | 5911 // lo is a Smi. Tag it and return. |
5892 __ Bind(&is_smi); | 5912 __ Bind(&is_smi); |
5893 __ SmiTag(lo); | 5913 __ mov(out_reg, ShifterOperand(value_lo)); |
5894 __ mov(out_reg, ShifterOperand(lo)); | 5914 __ SmiTag(out_reg); |
5895 __ b(&done); | 5915 __ b(&done); |
5896 | 5916 |
5897 // Not a smi. Box it. | 5917 // Not a smi. Box it. |
5898 __ Bind(¬_smi); | 5918 __ Bind(¬_smi); |
5899 __ TryAllocate( | 5919 __ TryAllocate( |
5900 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), | 5920 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
5901 slow_path->entry_label(), | 5921 slow_path->entry_label(), |
5902 out_reg, | 5922 out_reg, |
5903 lo); | 5923 tmp); |
5904 __ Bind(slow_path->exit_label()); | 5924 __ Bind(slow_path->exit_label()); |
5905 __ StoreDToOffset(dvalue0, out_reg, Mint::value_offset() - kHeapObjectTag); | 5925 __ StoreToOffset(kWord, |
| 5926 value_lo, |
| 5927 out_reg, |
| 5928 Mint::value_offset() - kHeapObjectTag); |
| 5929 __ StoreToOffset(kWord, |
| 5930 value_hi, |
| 5931 out_reg, |
| 5932 Mint::value_offset() - kHeapObjectTag + kWordSize); |
5906 __ Bind(&done); | 5933 __ Bind(&done); |
5907 } | 5934 } |
5908 | 5935 |
5909 | 5936 |
5910 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { | 5937 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const { |
5911 const intptr_t kNumInputs = 2; | 5938 const intptr_t kNumInputs = 2; |
5912 const intptr_t kNumTemps = | 5939 const intptr_t kNumTemps = 0; |
5913 FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
5914 LocationSummary* summary = | 5940 LocationSummary* summary = |
5915 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 5941 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
5916 summary->set_in(0, Location::RequiresFpuRegister()); | 5942 summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
5917 summary->set_in(1, Location::RequiresFpuRegister()); | 5943 Location::RequiresRegister())); |
5918 if (FLAG_throw_on_javascript_int_overflow) { | 5944 summary->set_in(1, Location::Pair(Location::RequiresRegister(), |
5919 summary->set_temp(0, Location::RequiresRegister()); | 5945 Location::RequiresRegister())); |
5920 summary->set_temp(1, Location::RequiresRegister()); | 5946 summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
5921 } | 5947 Location::RequiresRegister())); |
5922 if ((op_kind() == Token::kADD) || (op_kind() == Token::kSUB)) { | |
5923 // Need another temp for checking for overflow. | |
5924 summary->AddTemp(Location::RequiresFpuRegister()); | |
5925 summary->AddTemp(Location::FpuRegisterLocation(Q7)); | |
5926 } | |
5927 summary->set_out(0, Location::RequiresFpuRegister()); | |
5928 return summary; | 5948 return summary; |
5929 } | 5949 } |
5930 | 5950 |
5931 | 5951 |
5932 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5952 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5933 const QRegister left = locs()->in(0).fpu_reg(); | 5953 PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
5934 const QRegister right = locs()->in(1).fpu_reg(); | 5954 Register left_lo = left_pair->At(0).reg(); |
5935 const QRegister out = locs()->out(0).fpu_reg(); | 5955 Register left_hi = left_pair->At(1).reg(); |
| 5956 PairLocation* right_pair = locs()->in(1).AsPairLocation(); |
| 5957 Register right_lo = right_pair->At(0).reg(); |
| 5958 Register right_hi = right_pair->At(1).reg(); |
| 5959 PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| 5960 Register out_lo = out_pair->At(0).reg(); |
| 5961 Register out_hi = out_pair->At(1).reg(); |
5936 | 5962 |
5937 Label* deopt = NULL; | 5963 Label* deopt = NULL; |
5938 if (FLAG_throw_on_javascript_int_overflow) { | 5964 if (FLAG_throw_on_javascript_int_overflow) { |
5939 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp); | 5965 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp); |
5940 } | 5966 } |
5941 switch (op_kind()) { | 5967 switch (op_kind()) { |
5942 case Token::kBIT_AND: __ vandq(out, left, right); break; | 5968 case Token::kBIT_AND: { |
5943 case Token::kBIT_OR: __ vorrq(out, left, right); break; | 5969 __ and_(out_lo, left_lo, ShifterOperand(right_lo)); |
5944 case Token::kBIT_XOR: __ veorq(out, left, right); break; | 5970 __ and_(out_hi, left_hi, ShifterOperand(right_hi)); |
| 5971 } |
| 5972 break; |
| 5973 case Token::kBIT_OR: { |
| 5974 __ orr(out_lo, left_lo, ShifterOperand(right_lo)); |
| 5975 __ orr(out_hi, left_hi, ShifterOperand(right_hi)); |
| 5976 } |
| 5977 break; |
| 5978 case Token::kBIT_XOR: { |
| 5979 __ eor(out_lo, left_lo, ShifterOperand(right_lo)); |
| 5980 __ eor(out_hi, left_hi, ShifterOperand(right_hi)); |
| 5981 } |
| 5982 break; |
5945 case Token::kADD: | 5983 case Token::kADD: |
5946 case Token::kSUB: { | 5984 case Token::kSUB: { |
5947 const intptr_t tmpidx = FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
5948 const QRegister tmp = locs()->temp(tmpidx).fpu_reg(); | |
5949 const QRegister ro = locs()->temp(tmpidx + 1).fpu_reg(); | |
5950 ASSERT(ro == Q7); | |
5951 if (!FLAG_throw_on_javascript_int_overflow) { | 5985 if (!FLAG_throw_on_javascript_int_overflow) { |
5952 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp); | 5986 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp); |
5953 } | 5987 } |
5954 if (op_kind() == Token::kADD) { | 5988 if (op_kind() == Token::kADD) { |
5955 __ vaddqi(kWordPair, out, left, right); | 5989 __ adds(out_lo, left_lo, ShifterOperand(right_lo)); |
| 5990 __ adcs(out_hi, left_hi, ShifterOperand(right_hi)); |
5956 } else { | 5991 } else { |
5957 ASSERT(op_kind() == Token::kSUB); | 5992 ASSERT(op_kind() == Token::kSUB); |
5958 __ vsubqi(kWordPair, out, left, right); | 5993 __ subs(out_lo, left_lo, ShifterOperand(right_lo)); |
| 5994 __ sbcs(out_hi, left_hi, ShifterOperand(right_hi)); |
5959 } | 5995 } |
5960 __ veorq(ro, out, left); | 5996 // Deopt on overflow. |
5961 __ veorq(tmp, left, right); | 5997 __ b(deopt, VS); |
5962 __ vandq(ro, tmp, ro); | |
5963 __ vmovrs(TMP, OddSRegisterOf(EvenDRegisterOf(ro))); | |
5964 // If TMP < 0, there was overflow. | |
5965 __ cmp(TMP, ShifterOperand(0)); | |
5966 __ b(deopt, LT); | |
5967 break; | 5998 break; |
5968 } | 5999 } |
5969 default: UNREACHABLE(); break; | 6000 default: |
| 6001 UNREACHABLE(); |
| 6002 break; |
5970 } | 6003 } |
5971 if (FLAG_throw_on_javascript_int_overflow) { | 6004 if (FLAG_throw_on_javascript_int_overflow) { |
5972 const Register tmp1 = locs()->temp(0).reg(); | 6005 EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi); |
5973 const Register tmp2 = locs()->temp(1).reg(); | |
5974 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
5975 } | 6006 } |
5976 } | 6007 } |
5977 | 6008 |
5978 | 6009 |
5979 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { | 6010 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const { |
5980 const intptr_t kNumInputs = 2; | 6011 const intptr_t kNumInputs = 2; |
5981 const intptr_t kNumTemps = | 6012 const intptr_t kNumTemps = 1; |
5982 FLAG_throw_on_javascript_int_overflow ? 2 : 1; | |
5983 LocationSummary* summary = | 6013 LocationSummary* summary = |
5984 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 6014 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
5985 summary->set_in(0, Location::RequiresFpuRegister()); | 6015 summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| 6016 Location::RequiresRegister())); |
5986 summary->set_in(1, Location::WritableRegister()); | 6017 summary->set_in(1, Location::WritableRegister()); |
5987 summary->set_temp(0, Location::FpuRegisterLocation(Q7)); | 6018 summary->set_temp(0, Location::RequiresRegister()); |
5988 if (FLAG_throw_on_javascript_int_overflow) { | 6019 summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
5989 summary->set_temp(1, Location::RequiresRegister()); | 6020 Location::RequiresRegister())); |
5990 } | |
5991 summary->set_out(0, Location::RequiresFpuRegister()); | |
5992 return summary; | 6021 return summary; |
5993 } | 6022 } |
5994 | 6023 |
5995 | 6024 |
5996 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 6025 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5997 const QRegister value = locs()->in(0).fpu_reg(); | 6026 PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
5998 const Register shift = locs()->in(1).reg(); | 6027 Register left_lo = left_pair->At(0).reg(); |
5999 const QRegister temp = locs()->temp(0).fpu_reg(); | 6028 Register left_hi = left_pair->At(1).reg(); |
6000 ASSERT(temp == Q7); | 6029 Register shift = locs()->in(1).reg(); |
6001 const QRegister out = locs()->out(0).fpu_reg(); | 6030 PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
6002 const DRegister dtemp0 = EvenDRegisterOf(temp); | 6031 Register out_lo = out_pair->At(0).reg(); |
6003 const SRegister stemp0 = EvenSRegisterOf(dtemp0); | 6032 Register out_hi = out_pair->At(1).reg(); |
6004 const SRegister stemp1 = OddSRegisterOf(dtemp0); | 6033 Register temp = locs()->temp(0).reg(); |
6005 | 6034 |
6006 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp); | 6035 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp); |
6007 Label done; | 6036 Label done; |
6008 | 6037 |
| 6038 // Early out if shift is 0. |
6009 __ CompareImmediate(shift, 0); | 6039 __ CompareImmediate(shift, 0); |
6010 __ vmovq(out, value); | 6040 __ mov(out_lo, ShifterOperand(left_lo)); |
| 6041 __ mov(out_hi, ShifterOperand(left_hi)); |
6011 __ b(&done, EQ); | 6042 __ b(&done, EQ); |
| 6043 |
| 6044 // Untag shift count. |
6012 __ SmiUntag(shift); | 6045 __ SmiUntag(shift); |
6013 | 6046 |
6014 // vshlq takes the shift value from low byte. Deopt if shift is | 6047 // Deopt if shift is negative. |
6015 // outside of [0, 63]. | 6048 __ CompareImmediate(shift, 1); |
| 6049 __ b(deopt, LT); |
| 6050 |
| 6051 // Deopt if shift is larger than 63. |
6016 __ CompareImmediate(shift, 63); | 6052 __ CompareImmediate(shift, 63); |
6017 __ b(deopt, GT); | 6053 __ b(deopt, GT); |
6018 __ CompareImmediate(shift, 0); | |
6019 __ b(deopt, LT); | |
6020 | 6054 |
6021 __ veorq(temp, temp, temp); // Zero out temp. | |
6022 switch (op_kind()) { | 6055 switch (op_kind()) { |
6023 case Token::kSHR: { | 6056 case Token::kSHR: { |
6024 __ rsb(shift, shift, ShifterOperand(0)); // Negate shift. | 6057 __ cmp(shift, ShifterOperand(32)); |
6025 __ vmovsr(stemp0, shift); // Move the shift into the low S register. | 6058 |
6026 __ vshlqi(kWordPair, out, value, temp); | 6059 __ mov(out_lo, ShifterOperand(out_hi), HI); |
| 6060 __ Asr(out_hi, out_hi, 31, HI); |
| 6061 __ sub(shift, shift, ShifterOperand(32), HI); |
| 6062 |
| 6063 __ rsb(temp, shift, ShifterOperand(32)); |
| 6064 __ mov(temp, ShifterOperand(out_hi, LSL, temp)); |
| 6065 __ orr(out_lo, temp, ShifterOperand(out_lo, LSR, shift)); |
| 6066 __ Asr(out_hi, out_hi, shift); |
6027 break; | 6067 break; |
6028 } | 6068 } |
6029 case Token::kSHL: { | 6069 case Token::kSHL: { |
6030 __ vmovsr(stemp0, shift); // Move the shift into the low S register. | 6070 __ rsbs(temp, shift, ShifterOperand(32)); |
6031 __ vshlqu(kWordPair, out, value, temp); | 6071 __ sub(temp, shift, ShifterOperand(32), MI); |
| 6072 __ mov(out_hi, ShifterOperand(out_lo, LSL, temp), MI); |
| 6073 __ mov(out_hi, ShifterOperand(out_hi, LSL, shift), PL); |
| 6074 __ orr(out_hi, out_hi, ShifterOperand(out_lo, LSR, temp), PL); |
| 6075 __ mov(out_lo, ShifterOperand(out_lo, LSL, shift)); |
6032 | 6076 |
6033 // check for overflow by shifting back and comparing. | 6077 // Check for overflow. |
6034 __ rsb(shift, shift, ShifterOperand(0)); | 6078 |
6035 __ vmovsr(stemp0, shift); | 6079 // Copy high word from output. |
6036 __ vshlqi(kWordPair, temp, out, temp); | 6080 __ mov(temp, ShifterOperand(out_hi)); |
6037 __ vceqqi(kWord, temp, temp, value); | 6081 // Shift copy right. |
6038 // Low 64 bits of temp should be all 1's, otherwise temp != value and | 6082 __ Asr(temp, temp, shift); |
6039 // we deopt. | 6083 // Compare with high word from input. |
6040 __ vmovrs(shift, stemp0); | 6084 __ cmp(temp, ShifterOperand(left_hi)); |
6041 __ CompareImmediate(shift, -1); | 6085 // Overflow if they aren't equal. |
6042 __ b(deopt, NE); | |
6043 __ vmovrs(shift, stemp1); | |
6044 __ CompareImmediate(shift, -1); | |
6045 __ b(deopt, NE); | 6086 __ b(deopt, NE); |
6046 break; | 6087 break; |
6047 } | 6088 } |
6048 default: | 6089 default: |
6049 UNREACHABLE(); | 6090 UNREACHABLE(); |
6050 break; | 6091 break; |
6051 } | 6092 } |
6052 | 6093 |
6053 __ Bind(&done); | 6094 __ Bind(&done); |
6054 if (FLAG_throw_on_javascript_int_overflow) { | 6095 if (FLAG_throw_on_javascript_int_overflow) { |
6055 const Register tmp1 = locs()->in(1).reg(); | 6096 EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi); |
6056 const Register tmp2 = locs()->temp(1).reg(); | |
6057 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
6058 } | 6097 } |
6059 } | 6098 } |
6060 | 6099 |
6061 | 6100 |
6062 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { | 6101 LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const { |
6063 const intptr_t kNumInputs = 1; | 6102 const intptr_t kNumInputs = 1; |
6064 const intptr_t kNumTemps = | 6103 const intptr_t kNumTemps = 0; |
6065 FLAG_throw_on_javascript_int_overflow ? 2 : 0; | |
6066 LocationSummary* summary = | 6104 LocationSummary* summary = |
6067 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 6105 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
6068 summary->set_in(0, Location::RequiresFpuRegister()); | 6106 summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
6069 summary->set_out(0, Location::RequiresFpuRegister()); | 6107 Location::RequiresRegister())); |
6070 if (FLAG_throw_on_javascript_int_overflow) { | 6108 summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
6071 summary->set_temp(0, Location::RequiresRegister()); | 6109 Location::RequiresRegister())); |
6072 summary->set_temp(1, Location::RequiresRegister()); | |
6073 } | |
6074 return summary; | 6110 return summary; |
6075 } | 6111 } |
6076 | 6112 |
6077 | 6113 |
6078 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 6114 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
6079 ASSERT(op_kind() == Token::kBIT_NOT); | 6115 ASSERT(op_kind() == Token::kBIT_NOT); |
6080 const QRegister value = locs()->in(0).fpu_reg(); | 6116 PairLocation* left_pair = locs()->in(0).AsPairLocation(); |
6081 const QRegister out = locs()->out(0).fpu_reg(); | 6117 Register left_lo = left_pair->At(0).reg(); |
| 6118 Register left_hi = left_pair->At(1).reg(); |
| 6119 |
| 6120 PairLocation* out_pair = locs()->out(0).AsPairLocation(); |
| 6121 Register out_lo = out_pair->At(0).reg(); |
| 6122 Register out_hi = out_pair->At(1).reg(); |
| 6123 |
6082 Label* deopt = NULL; | 6124 Label* deopt = NULL; |
| 6125 |
6083 if (FLAG_throw_on_javascript_int_overflow) { | 6126 if (FLAG_throw_on_javascript_int_overflow) { |
6084 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp); | 6127 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp); |
6085 } | 6128 } |
6086 __ vmvnq(out, value); | 6129 __ mvn(out_lo, ShifterOperand(left_lo)); |
| 6130 __ mvn(out_hi, ShifterOperand(left_hi)); |
6087 if (FLAG_throw_on_javascript_int_overflow) { | 6131 if (FLAG_throw_on_javascript_int_overflow) { |
6088 const Register tmp1 = locs()->temp(0).reg(); | 6132 EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi); |
6089 const Register tmp2 = locs()->temp(1).reg(); | |
6090 EmitJavascriptIntOverflowCheck(compiler, deopt, out, tmp1, tmp2); | |
6091 } | 6133 } |
6092 } | 6134 } |
6093 | 6135 |
6094 | 6136 |
6095 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { | 6137 LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const { |
6096 return new LocationSummary(0, 0, LocationSummary::kCall); | 6138 return new LocationSummary(0, 0, LocationSummary::kCall); |
6097 } | 6139 } |
6098 | 6140 |
6099 | 6141 |
6100 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 6142 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6290 compiler->GenerateCall(token_pos(), | 6332 compiler->GenerateCall(token_pos(), |
6291 &label, | 6333 &label, |
6292 PcDescriptors::kOther, | 6334 PcDescriptors::kOther, |
6293 locs()); | 6335 locs()); |
6294 __ Drop(ArgumentCount()); // Discard arguments. | 6336 __ Drop(ArgumentCount()); // Discard arguments. |
6295 } | 6337 } |
6296 | 6338 |
6297 } // namespace dart | 6339 } // namespace dart |
6298 | 6340 |
6299 #endif // defined TARGET_ARCH_ARM | 6341 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |