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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 297 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
298 locs->set_in(0, Location::RegisterOrConstant(left())); | 298 locs->set_in(0, Location::RegisterOrConstant(left())); |
299 // Only one input can be a constant operand. The case of two constant | 299 // Only one input can be a constant operand. The case of two constant |
300 // operands should be handled by constant propagation. | 300 // operands should be handled by constant propagation. |
301 locs->set_in(1, locs->in(0).IsConstant() | 301 locs->set_in(1, locs->in(0).IsConstant() |
302 ? Location::RequiresRegister() | 302 ? Location::RequiresRegister() |
303 : Location::RegisterOrConstant(right())); | 303 : Location::RegisterOrConstant(right())); |
304 locs->set_out(Location::RequiresRegister()); | 304 locs->set_out(Location::RequiresRegister()); |
305 return locs; | 305 return locs; |
306 } | 306 } |
307 if (IsCheckedStrictEqual()) { | 307 UNREACHABLE(); |
308 const intptr_t kNumTemps = 1; | 308 return NULL; |
309 LocationSummary* locs = | |
310 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
311 locs->set_in(0, Location::RequiresRegister()); | |
312 locs->set_in(1, Location::RequiresRegister()); | |
313 locs->set_temp(0, Location::RequiresRegister()); | |
314 locs->set_out(Location::RequiresRegister()); | |
315 return locs; | |
316 } | |
317 if (IsPolymorphic()) { | |
318 const intptr_t kNumTemps = 1; | |
319 LocationSummary* locs = | |
320 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
321 locs->set_in(0, Location::RegisterLocation(A1)); | |
322 locs->set_in(1, Location::RegisterLocation(A0)); | |
323 locs->set_temp(0, Location::RegisterLocation(T0)); | |
324 locs->set_out(Location::RegisterLocation(V0)); | |
325 return locs; | |
326 } | |
327 const intptr_t kNumTemps = 1; | |
328 LocationSummary* locs = | |
329 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
330 locs->set_in(0, Location::RegisterLocation(A1)); | |
331 locs->set_in(1, Location::RegisterLocation(A0)); | |
332 locs->set_temp(0, Location::RegisterLocation(T0)); | |
333 locs->set_out(Location::RegisterLocation(V0)); | |
334 return locs; | |
335 } | |
336 | |
337 | |
338 // A1: left. | |
339 // A0: right. | |
340 // Uses T0 to load ic_call_data. | |
341 // Result in V0. | |
342 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | |
343 intptr_t deopt_id, | |
344 intptr_t token_pos, | |
345 Token::Kind kind, | |
346 LocationSummary* locs, | |
347 const ICData& original_ic_data) { | |
348 if (!compiler->is_optimizing()) { | |
349 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | |
350 deopt_id, | |
351 token_pos); | |
352 } | |
353 const int kNumberOfArguments = 2; | |
354 const Array& kNoArgumentNames = Object::null_array(); | |
355 const int kNumArgumentsChecked = 2; | |
356 | |
357 __ TraceSimMsg("EmitEqualityAsInstanceCall"); | |
358 __ Comment("EmitEqualityAsInstanceCall"); | |
359 | |
360 ICData& equality_ic_data = ICData::ZoneHandle(); | |
361 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | |
362 ASSERT(!original_ic_data.IsNull()); | |
363 if (original_ic_data.NumberOfChecks() == 0) { | |
364 // IC call for reoptimization populates original ICData. | |
365 equality_ic_data = original_ic_data.raw(); | |
366 } else { | |
367 // Megamorphic call. | |
368 equality_ic_data = original_ic_data.AsUnaryClassChecks(); | |
369 } | |
370 } else { | |
371 const Array& arguments_descriptor = | |
372 Array::Handle(ArgumentsDescriptor::New(kNumberOfArguments, | |
373 kNoArgumentNames)); | |
374 equality_ic_data = ICData::New(compiler->parsed_function().function(), | |
375 Symbols::EqualOperator(), | |
376 arguments_descriptor, | |
377 deopt_id, | |
378 kNumArgumentsChecked); | |
379 } | |
380 compiler->GenerateInstanceCall(deopt_id, | |
381 token_pos, | |
382 kNumberOfArguments, | |
383 kNoArgumentNames, | |
384 locs, | |
385 equality_ic_data); | |
386 if (kind == Token::kNE) { | |
387 Label true_label, done; | |
388 // Negate the condition: true label returns false and vice versa. | |
389 __ BranchEqual(V0, Bool::True(), &true_label); | |
390 __ LoadObject(V0, Bool::True()); | |
391 __ b(&done); | |
392 __ Bind(&true_label); | |
393 __ LoadObject(V0, Bool::False()); | |
394 __ Bind(&done); | |
395 } | |
396 } | 309 } |
397 | 310 |
398 | 311 |
399 static void LoadValueCid(FlowGraphCompiler* compiler, | 312 static void LoadValueCid(FlowGraphCompiler* compiler, |
400 Register value_cid_reg, | 313 Register value_cid_reg, |
401 Register value_reg, | 314 Register value_reg, |
402 Label* value_is_smi = NULL) { | 315 Label* value_is_smi = NULL) { |
403 __ TraceSimMsg("LoadValueCid"); | 316 __ TraceSimMsg("LoadValueCid"); |
404 Label done; | 317 Label done; |
405 if (value_is_smi == NULL) { | 318 if (value_is_smi == NULL) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 case GE: __ beq(CMPRES1, ZR, is_true); break; | 354 case GE: __ beq(CMPRES1, ZR, is_true); break; |
442 case LT: __ bne(CMPRES1, ZR, is_true); break; | 355 case LT: __ bne(CMPRES1, ZR, is_true); break; |
443 case LE: __ beq(CMPRES2, ZR, is_true); break; | 356 case LE: __ beq(CMPRES2, ZR, is_true); break; |
444 default: | 357 default: |
445 UNREACHABLE(); | 358 UNREACHABLE(); |
446 break; | 359 break; |
447 } | 360 } |
448 } | 361 } |
449 | 362 |
450 | 363 |
451 // A1: left, also on stack. | |
452 // A0: right, also on stack. | |
453 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | |
454 const ICData& orig_ic_data, | |
455 LocationSummary* locs, | |
456 BranchInstr* branch, | |
457 Token::Kind kind, | |
458 intptr_t deopt_id, | |
459 intptr_t token_pos) { | |
460 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
461 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | |
462 ASSERT(ic_data.NumberOfChecks() > 0); | |
463 ASSERT(ic_data.num_args_tested() == 1); | |
464 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | |
465 Register left = locs->in(0).reg(); | |
466 Register right = locs->in(1).reg(); | |
467 ASSERT(left == A1); | |
468 ASSERT(right == A0); | |
469 Register temp = locs->temp(0).reg(); | |
470 | |
471 __ TraceSimMsg("EmitEqualityAsPolymorphicCall"); | |
472 __ Comment("EmitEqualityAsPolymorphicCall"); | |
473 | |
474 LoadValueCid(compiler, temp, left, | |
475 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); | |
476 // 'temp' contains class-id of the left argument. | |
477 ObjectStore* object_store = Isolate::Current()->object_store(); | |
478 Condition cond = TokenKindToSmiCondition(kind); | |
479 Label done; | |
480 const intptr_t len = ic_data.NumberOfChecks(); | |
481 for (intptr_t i = 0; i < len; i++) { | |
482 // Assert that the Smi is at position 0, if at all. | |
483 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); | |
484 Label next_test; | |
485 if (i < len - 1) { | |
486 __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), &next_test); | |
487 } else { | |
488 __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt); | |
489 } | |
490 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | |
491 if (target.Owner() == object_store->object_class()) { | |
492 // Object.== is same as ===. | |
493 __ Drop(2); | |
494 __ slt(CMPRES1, left, right); | |
495 __ slt(CMPRES2, right, left); | |
496 if (branch != NULL) { | |
497 branch->EmitBranchOnCondition(compiler, cond); | |
498 } else { | |
499 Register result = locs->out().reg(); | |
500 Label load_true; | |
501 EmitBranchAfterCompare(compiler, cond, &load_true); | |
502 __ LoadObject(result, Bool::False()); | |
503 __ b(&done); | |
504 __ Bind(&load_true); | |
505 __ LoadObject(result, Bool::True()); | |
506 } | |
507 } else { | |
508 const int kNumberOfArguments = 2; | |
509 const Array& kNoArgumentNames = Object::null_array(); | |
510 compiler->GenerateStaticCall(deopt_id, | |
511 token_pos, | |
512 target, | |
513 kNumberOfArguments, | |
514 kNoArgumentNames, | |
515 locs); | |
516 if (branch == NULL) { | |
517 if (kind == Token::kNE) { | |
518 Label is_true; | |
519 __ CompareObject(CMPRES1, CMPRES2, V0, Bool::True()); | |
520 __ beq(CMPRES, CMPRES2, &is_true); | |
521 __ LoadObject(V0, Bool::True()); | |
522 __ b(&done); | |
523 __ Bind(&is_true); | |
524 __ LoadObject(V0, Bool::False()); | |
525 } | |
526 } else { | |
527 if (branch->is_checked()) { | |
528 EmitAssertBoolean(V0, token_pos, deopt_id, locs, compiler); | |
529 } | |
530 __ CompareObject(CMPRES1, CMPRES2, V0, Bool::True()); | |
531 branch->EmitBranchOnCondition(compiler, cond); | |
532 } | |
533 } | |
534 if (i < len - 1) { | |
535 __ b(&done); | |
536 __ Bind(&next_test); | |
537 } | |
538 } | |
539 __ Bind(&done); | |
540 } | |
541 | |
542 | |
543 // Emit code when ICData's targets are all Object == (which is ===). | |
544 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, | |
545 const ICData& orig_ic_data, | |
546 const LocationSummary& locs, | |
547 Token::Kind kind, | |
548 BranchInstr* branch, | |
549 intptr_t deopt_id) { | |
550 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
551 Register left = locs.in(0).reg(); | |
552 Register right = locs.in(1).reg(); | |
553 Register temp = locs.temp(0).reg(); | |
554 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | |
555 | |
556 __ Comment("CheckedStrictEqual"); | |
557 | |
558 __ andi(CMPRES, left, Immediate(kSmiTagMask)); | |
559 __ beq(CMPRES, ZR, deopt); | |
560 // 'left' is not Smi. | |
561 Label identity_compare; | |
562 __ LoadImmediate(CMPRES1, reinterpret_cast<int32_t>(Object::null())); | |
563 __ beq(right, CMPRES1, &identity_compare); | |
564 __ beq(left, CMPRES1, &identity_compare); | |
565 | |
566 __ LoadClassId(temp, left); | |
567 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | |
568 const intptr_t len = ic_data.NumberOfChecks(); | |
569 for (intptr_t i = 0; i < len; i++) { | |
570 if (i == (len - 1)) { | |
571 __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt); | |
572 } else { | |
573 __ BranchEqual(temp, ic_data.GetReceiverClassIdAt(i), &identity_compare); | |
574 } | |
575 } | |
576 __ Bind(&identity_compare); | |
577 __ subu(CMPRES1, left, right); | |
578 if (branch == NULL) { | |
579 Label done, is_equal; | |
580 Register result = locs.out().reg(); | |
581 __ beq(CMPRES, ZR, &is_equal); | |
582 // Not equal. | |
583 __ LoadObject(result, Bool::Get(kind != Token::kEQ)); | |
584 __ b(&done); | |
585 __ Bind(&is_equal); | |
586 __ LoadObject(result, Bool::Get(kind == Token::kEQ)); | |
587 __ Bind(&done); | |
588 | |
589 } else { | |
590 Condition cond = TokenKindToSmiCondition(kind); | |
591 __ mov(CMPRES2, ZR); | |
592 branch->EmitBranchOnCondition(compiler, cond); | |
593 } | |
594 } | |
595 | |
596 | |
597 // First test if receiver is NULL, in which case === is applied. | |
598 // If type feedback was provided (lists of <class-id, target>), do a | |
599 // type by type check (either === or static call to the operator. | |
600 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | |
601 LocationSummary* locs, | |
602 Token::Kind kind, | |
603 BranchInstr* branch, | |
604 const ICData& ic_data, | |
605 intptr_t deopt_id, | |
606 intptr_t token_pos) { | |
607 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
608 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | |
609 Register left = locs->in(0).reg(); | |
610 Register right = locs->in(1).reg(); | |
611 __ TraceSimMsg("EmitGenericEqualityCompare"); | |
612 __ Comment("EmitGenericEqualityCompare"); | |
613 ASSERT(left == A1); | |
614 ASSERT(right == A0); | |
615 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
616 __ sw(A1, Address(SP, 1 * kWordSize)); | |
617 __ sw(A0, Address(SP, 0 * kWordSize)); | |
618 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, | |
619 deopt_id, token_pos); | |
620 } | |
621 | |
622 | |
623 static Condition FlipCondition(Condition condition) { | 364 static Condition FlipCondition(Condition condition) { |
624 switch (condition) { | 365 switch (condition) { |
625 case EQ: return EQ; | 366 case EQ: return EQ; |
626 case NE: return NE; | 367 case NE: return NE; |
627 case LT: return GT; | 368 case LT: return GT; |
628 case LE: return GE; | 369 case LE: return GE; |
629 case GT: return LT; | 370 case GT: return LT; |
630 case GE: return LE; | 371 case GE: return LE; |
631 default: | 372 default: |
632 UNREACHABLE(); | 373 UNREACHABLE(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 return; | 473 return; |
733 } | 474 } |
734 if (operation_cid() == kMintCid) { | 475 if (operation_cid() == kMintCid) { |
735 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); | 476 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); |
736 return; | 477 return; |
737 } | 478 } |
738 if (operation_cid() == kDoubleCid) { | 479 if (operation_cid() == kDoubleCid) { |
739 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); | 480 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); |
740 return; | 481 return; |
741 } | 482 } |
742 if (IsCheckedStrictEqual()) { | 483 UNREACHABLE(); |
743 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch, | |
744 deopt_id()); | |
745 return; | |
746 } | |
747 if (IsPolymorphic()) { | |
748 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), | |
749 deopt_id(), token_pos()); | |
750 return; | |
751 } | |
752 Register left = locs()->in(0).reg(); | |
753 Register right = locs()->in(1).reg(); | |
754 ASSERT(left == A1); | |
755 ASSERT(right == A0); | |
756 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
757 __ sw(A1, Address(SP, 1 * kWordSize)); | |
758 __ sw(A0, Address(SP, 0 * kWordSize)); | |
759 EmitEqualityAsInstanceCall(compiler, | |
760 deopt_id(), | |
761 token_pos(), | |
762 kind(), | |
763 locs(), | |
764 *ic_data()); | |
765 ASSERT(locs()->out().reg() == V0); | |
766 } | 484 } |
767 | 485 |
768 | 486 |
769 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 487 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
770 BranchInstr* branch) { | 488 BranchInstr* branch) { |
771 __ TraceSimMsg("EqualityCompareInstr"); | 489 __ TraceSimMsg("EqualityCompareInstr"); |
772 __ Comment("EqualityCompareInstr:BranchCode"); | 490 __ Comment("EqualityCompareInstr:BranchCode"); |
773 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 491 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
774 if (operation_cid() == kSmiCid) { | 492 if (operation_cid() == kSmiCid) { |
775 // Deoptimizes if both arguments not Smi. | 493 // Deoptimizes if both arguments not Smi. |
776 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | 494 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); |
777 return; | 495 return; |
778 } | 496 } |
779 if (operation_cid() == kMintCid) { | 497 if (operation_cid() == kMintCid) { |
780 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); | 498 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); |
781 return; | 499 return; |
782 } | 500 } |
783 if (operation_cid() == kDoubleCid) { | 501 if (operation_cid() == kDoubleCid) { |
784 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | 502 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); |
785 return; | 503 return; |
786 } | 504 } |
787 if (IsCheckedStrictEqual()) { | 505 UNREACHABLE(); |
788 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, | |
789 deopt_id()); | |
790 return; | |
791 } | |
792 if (IsPolymorphic()) { | |
793 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), | |
794 deopt_id(), token_pos()); | |
795 return; | |
796 } | |
797 Register left = locs()->in(0).reg(); | |
798 Register right = locs()->in(1).reg(); | |
799 ASSERT(left == A1); | |
800 ASSERT(right == A0); | |
801 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
802 __ sw(A1, Address(SP, 1 * kWordSize)); | |
803 __ sw(A0, Address(SP, 0 * kWordSize)); | |
804 EmitEqualityAsInstanceCall(compiler, | |
805 deopt_id(), | |
806 token_pos(), | |
807 Token::kEQ, // kNE reverse occurs at branch. | |
808 locs(), | |
809 *ic_data()); | |
810 if (branch->is_checked()) { | |
811 EmitAssertBoolean(V0, token_pos(), deopt_id(), locs(), compiler); | |
812 } | |
813 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; | |
814 __ CompareObject(CMPRES1, CMPRES2, V0, Bool::True()); | |
815 branch->EmitBranchOnCondition(compiler, branch_condition); | |
816 } | 506 } |
817 | 507 |
818 | 508 |
819 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 509 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
820 const intptr_t kNumInputs = 2; | 510 const intptr_t kNumInputs = 2; |
821 const intptr_t kNumTemps = 0; | 511 const intptr_t kNumTemps = 0; |
822 if (operation_cid() == kMintCid) { | 512 if (operation_cid() == kMintCid) { |
823 const intptr_t kNumTemps = 2; | 513 const intptr_t kNumTemps = 2; |
824 LocationSummary* locs = | 514 LocationSummary* locs = |
825 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 515 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
(...skipping 3264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4090 compiler->GenerateCall(token_pos(), | 3780 compiler->GenerateCall(token_pos(), |
4091 &label, | 3781 &label, |
4092 PcDescriptors::kOther, | 3782 PcDescriptors::kOther, |
4093 locs()); | 3783 locs()); |
4094 __ Drop(2); // Discard type arguments and receiver. | 3784 __ Drop(2); // Discard type arguments and receiver. |
4095 } | 3785 } |
4096 | 3786 |
4097 } // namespace dart | 3787 } // namespace dart |
4098 | 3788 |
4099 #endif // defined TARGET_ARCH_MIPS | 3789 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |