| 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 "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 Register obj = locs()->in(0).reg(); | 261 Register obj = locs()->in(0).reg(); |
| 262 Register result = locs()->out().reg(); | 262 Register result = locs()->out().reg(); |
| 263 | 263 |
| 264 __ TraceSimMsg("AssertBooleanInstr"); | 264 __ TraceSimMsg("AssertBooleanInstr"); |
| 265 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler); | 265 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler); |
| 266 ASSERT(obj == result); | 266 ASSERT(obj == result); |
| 267 } | 267 } |
| 268 | 268 |
| 269 | 269 |
| 270 LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const { | 270 LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const { |
| 271 UNIMPLEMENTED(); | 271 const intptr_t kNumInputs = 1; |
| 272 return NULL; | 272 const intptr_t kNumTemps = 0; |
| 273 LocationSummary* locs = |
| 274 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 275 locs->set_in(0, Location::RegisterLocation(T0)); |
| 276 locs->set_out(Location::RegisterLocation(T0)); |
| 277 return locs; |
| 273 } | 278 } |
| 274 | 279 |
| 275 | 280 |
| 276 void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 281 void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 277 UNIMPLEMENTED(); | 282 Register saved_args_desc = locs()->in(0).reg(); |
| 283 Register result = locs()->out().reg(); |
| 284 |
| 285 __ TraceSimMsg("ArgumentDefinitionTestInstr"); |
| 286 |
| 287 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 288 // Push the result place holder initialized to NULL. |
| 289 __ LoadObject(TMP1, Object::ZoneHandle()); |
| 290 __ sw(TMP1, Address(SP, 3 * kWordSize)); |
| 291 __ LoadImmediate(TMP1, Smi::RawValue(formal_parameter_index())); |
| 292 __ sw(TMP1, Address(SP, 2 * kWordSize)); |
| 293 __ LoadObject(TMP1, formal_parameter_name()); |
| 294 __ sw(TMP1, Address(SP, 1 * kWordSize)); |
| 295 __ sw(saved_args_desc, Address(SP, 0 * kWordSize)); |
| 296 compiler->GenerateCallRuntime(token_pos(), |
| 297 deopt_id(), |
| 298 kArgumentDefinitionTestRuntimeEntry, |
| 299 locs()); |
| 300 __ lw(result, Address(SP, 3 * kWordSize)); // Pop bool result. |
| 301 __ addiu(SP, SP, Immediate(4 * kWordSize)); |
| 278 } | 302 } |
| 279 | 303 |
| 280 | 304 |
| 281 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { | 305 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { |
| 282 const intptr_t kNumInputs = 2; | 306 const intptr_t kNumInputs = 2; |
| 283 const bool is_checked_strict_equal = | 307 const bool is_checked_strict_equal = |
| 284 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 308 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 285 if (receiver_class_id() == kMintCid) { | 309 if (receiver_class_id() == kMintCid) { |
| 286 const intptr_t kNumTemps = 1; | 310 const intptr_t kNumTemps = 1; |
| 287 LocationSummary* locs = | 311 LocationSummary* locs = |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 // A1: left. | 372 // A1: left. |
| 349 // A0: right. | 373 // A0: right. |
| 350 // Uses T0 to load ic_call_data. | 374 // Uses T0 to load ic_call_data. |
| 351 // Result in V0. | 375 // Result in V0. |
| 352 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 376 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 353 intptr_t deopt_id, | 377 intptr_t deopt_id, |
| 354 intptr_t token_pos, | 378 intptr_t token_pos, |
| 355 Token::Kind kind, | 379 Token::Kind kind, |
| 356 LocationSummary* locs, | 380 LocationSummary* locs, |
| 357 const ICData& original_ic_data) { | 381 const ICData& original_ic_data) { |
| 358 __ TraceSimMsg("EmitEqualityAsInstanceCall"); | |
| 359 if (!compiler->is_optimizing()) { | 382 if (!compiler->is_optimizing()) { |
| 360 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 383 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 361 deopt_id, | 384 deopt_id, |
| 362 token_pos); | 385 token_pos); |
| 363 } | 386 } |
| 364 const int kNumberOfArguments = 2; | 387 const int kNumberOfArguments = 2; |
| 365 const Array& kNoArgumentNames = Array::Handle(); | 388 const Array& kNoArgumentNames = Array::Handle(); |
| 366 const int kNumArgumentsChecked = 2; | 389 const int kNumArgumentsChecked = 2; |
| 367 | 390 |
| 391 __ TraceSimMsg("EmitEqualityAsInstanceCall"); |
| 368 Label check_identity; | 392 Label check_identity; |
| 393 __ lw(A1, Address(SP, 1 * kWordSize)); |
| 394 __ lw(A0, Address(SP, 0 * kWordSize)); |
| 369 __ beq(A1, NULLREG, &check_identity); | 395 __ beq(A1, NULLREG, &check_identity); |
| 370 __ beq(A0, NULLREG, &check_identity); | 396 __ beq(A0, NULLREG, &check_identity); |
| 371 | 397 |
| 372 ICData& equality_ic_data = ICData::ZoneHandle(); | 398 ICData& equality_ic_data = ICData::ZoneHandle(); |
| 373 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | 399 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { |
| 374 ASSERT(!original_ic_data.IsNull()); | 400 ASSERT(!original_ic_data.IsNull()); |
| 375 if (original_ic_data.NumberOfChecks() == 0) { | 401 if (original_ic_data.NumberOfChecks() == 0) { |
| 376 // IC call for reoptimization populates original ICData. | 402 // IC call for reoptimization populates original ICData. |
| 377 equality_ic_data = original_ic_data.raw(); | 403 equality_ic_data = original_ic_data.raw(); |
| 378 } else { | 404 } else { |
| 379 // Megamorphic call. | 405 // Megamorphic call. |
| 380 equality_ic_data = original_ic_data.AsUnaryClassChecks(); | 406 equality_ic_data = original_ic_data.AsUnaryClassChecks(); |
| 381 } | 407 } |
| 382 } else { | 408 } else { |
| 383 equality_ic_data = ICData::New(compiler->parsed_function().function(), | 409 equality_ic_data = ICData::New(compiler->parsed_function().function(), |
| 384 Symbols::EqualOperator(), | 410 Symbols::EqualOperator(), |
| 385 deopt_id, | 411 deopt_id, |
| 386 kNumArgumentsChecked); | 412 kNumArgumentsChecked); |
| 387 } | 413 } |
| 388 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
| 389 __ sw(A1, Address(SP, 1 * kWordSize)); | |
| 390 __ sw(A0, Address(SP, 0 * kWordSize)); | |
| 391 compiler->GenerateInstanceCall(deopt_id, | 414 compiler->GenerateInstanceCall(deopt_id, |
| 392 token_pos, | 415 token_pos, |
| 393 kNumberOfArguments, | 416 kNumberOfArguments, |
| 394 kNoArgumentNames, | 417 kNoArgumentNames, |
| 395 locs, | 418 locs, |
| 396 equality_ic_data); | 419 equality_ic_data); |
| 397 Label check_ne; | 420 Label check_ne; |
| 398 __ b(&check_ne); | 421 __ b(&check_ne); |
| 399 | 422 |
| 400 __ Bind(&check_identity); | 423 __ Bind(&check_identity); |
| 401 Label equality_done; | 424 Label equality_done; |
| 402 if (compiler->is_optimizing()) { | 425 if (compiler->is_optimizing()) { |
| 403 // No need to update IC data. | 426 // No need to update IC data. |
| 404 Label is_true; | 427 Label is_true; |
| 428 __ lw(A1, Address(SP, 1 * kWordSize)); |
| 429 __ lw(A0, Address(SP, 0 * kWordSize)); |
| 430 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 405 __ beq(A1, A0, &is_true); | 431 __ beq(A1, A0, &is_true); |
| 406 __ LoadObject(V0, (kind == Token::kEQ) ? Bool::False() : Bool::True()); | 432 __ LoadObject(V0, (kind == Token::kEQ) ? Bool::False() : Bool::True()); |
| 407 __ b(&equality_done); | 433 __ b(&equality_done); |
| 408 __ Bind(&is_true); | 434 __ Bind(&is_true); |
| 409 __ LoadObject(V0, (kind == Token::kEQ) ? Bool::True() : Bool::False()); | 435 __ LoadObject(V0, (kind == Token::kEQ) ? Bool::True() : Bool::False()); |
| 410 if (kind == Token::kNE) { | 436 if (kind == Token::kNE) { |
| 411 // Skip not-equal result conversion. | 437 // Skip not-equal result conversion. |
| 412 __ b(&equality_done); | 438 __ b(&equality_done); |
| 413 } | 439 } |
| 414 } else { | 440 } else { |
| 415 // Call stub, load IC data in register. The stub will update ICData if | 441 // Call stub, load IC data in register. The stub will update ICData if |
| 416 // necessary. | 442 // necessary. |
| 417 Register ic_data_reg = locs->temp(0).reg(); | 443 Register ic_data_reg = locs->temp(0).reg(); |
| 418 ASSERT(ic_data_reg == T0); // Stub depends on it. | 444 ASSERT(ic_data_reg == T0); // Stub depends on it. |
| 419 __ LoadObject(ic_data_reg, equality_ic_data); | 445 __ LoadObject(ic_data_reg, equality_ic_data); |
| 420 // Pass left in A1 and right in A0. | 446 // Pass left in A1 and right in A0. |
| 421 compiler->GenerateCall(token_pos, | 447 compiler->GenerateCall(token_pos, |
| 422 &StubCode::EqualityWithNullArgLabel(), | 448 &StubCode::EqualityWithNullArgLabel(), |
| 423 PcDescriptors::kRuntimeCall, | 449 PcDescriptors::kRuntimeCall, |
| 424 locs); | 450 locs); |
| 451 __ Drop(2); |
| 425 } | 452 } |
| 426 __ Bind(&check_ne); | 453 __ Bind(&check_ne); |
| 427 if (kind == Token::kNE) { | 454 if (kind == Token::kNE) { |
| 428 Label true_label, done; | 455 Label true_label, done; |
| 429 // Negate the condition: true label returns false and vice versa. | 456 // Negate the condition: true label returns false and vice versa. |
| 430 __ BranchEqual(V0, Bool::True(), &true_label); | 457 __ BranchEqual(V0, Bool::True(), &true_label); |
| 431 __ LoadObject(V0, Bool::True()); | 458 __ LoadObject(V0, Bool::True()); |
| 432 __ b(&done); | 459 __ b(&done); |
| 433 __ Bind(&true_label); | 460 __ Bind(&true_label); |
| 434 __ LoadObject(V0, Bool::False()); | 461 __ LoadObject(V0, Bool::False()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 451 if (value_is_smi == NULL) { | 478 if (value_is_smi == NULL) { |
| 452 __ beq(TMP1, ZR, &done); | 479 __ beq(TMP1, ZR, &done); |
| 453 } else { | 480 } else { |
| 454 __ beq(TMP1, ZR, value_is_smi); | 481 __ beq(TMP1, ZR, value_is_smi); |
| 455 } | 482 } |
| 456 __ LoadClassId(value_cid_reg, value_reg); | 483 __ LoadClassId(value_cid_reg, value_reg); |
| 457 __ Bind(&done); | 484 __ Bind(&done); |
| 458 } | 485 } |
| 459 | 486 |
| 460 | 487 |
| 488 static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| 489 switch (kind) { |
| 490 case Token::kEQ: return EQ; |
| 491 case Token::kNE: return NE; |
| 492 case Token::kLT: return LT; |
| 493 case Token::kGT: return GT; |
| 494 case Token::kLTE: return LE; |
| 495 case Token::kGTE: return GE; |
| 496 default: |
| 497 UNREACHABLE(); |
| 498 return VS; |
| 499 } |
| 500 } |
| 501 |
| 502 |
| 503 // Branches on condition c assuming comparison results in CMPRES and TMP1. |
| 504 static void EmitBranchAfterCompare( |
| 505 FlowGraphCompiler* compiler, Condition c, Label* is_true) { |
| 506 switch (c) { |
| 507 case EQ: __ beq(CMPRES, TMP1, is_true); break; |
| 508 case NE: __ bne(CMPRES, TMP1, is_true); break; |
| 509 case GT: __ bne(TMP1, ZR, is_true); break; |
| 510 case GE: __ beq(CMPRES, ZR, is_true); break; |
| 511 case LT: __ bne(CMPRES, ZR, is_true); break; |
| 512 case LE: __ beq(TMP1, ZR, is_true); break; |
| 513 default: |
| 514 UNREACHABLE(); |
| 515 break; |
| 516 } |
| 517 } |
| 518 |
| 519 |
| 520 // A1: left, also on stack. |
| 521 // A0: right, also on stack. |
| 522 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 523 const ICData& orig_ic_data, |
| 524 LocationSummary* locs, |
| 525 BranchInstr* branch, |
| 526 Token::Kind kind, |
| 527 intptr_t deopt_id, |
| 528 intptr_t token_pos) { |
| 529 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 530 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); |
| 531 ASSERT(ic_data.NumberOfChecks() > 0); |
| 532 ASSERT(ic_data.num_args_tested() == 1); |
| 533 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); |
| 534 Register left = locs->in(0).reg(); |
| 535 Register right = locs->in(1).reg(); |
| 536 ASSERT(left == A1); |
| 537 ASSERT(right == A0); |
| 538 Register temp = locs->temp(0).reg(); |
| 539 |
| 540 __ TraceSimMsg("EmitEqualityAsPolymorphicCall"); |
| 541 |
| 542 LoadValueCid(compiler, temp, left, |
| 543 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); |
| 544 // 'temp' contains class-id of the left argument. |
| 545 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 546 Condition cond = TokenKindToSmiCondition(kind); |
| 547 Label done; |
| 548 const intptr_t len = ic_data.NumberOfChecks(); |
| 549 for (intptr_t i = 0; i < len; i++) { |
| 550 // Assert that the Smi is at position 0, if at all. |
| 551 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); |
| 552 Label next_test; |
| 553 if (i < len - 1) { |
| 554 __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), &next_test); |
| 555 } else { |
| 556 __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt); |
| 557 } |
| 558 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
| 559 if (target.Owner() == object_store->object_class()) { |
| 560 // Object.== is same as ===. |
| 561 __ Drop(2); |
| 562 __ slt(CMPRES, left, right); |
| 563 __ slt(TMP1, right, left); |
| 564 if (branch != NULL) { |
| 565 branch->EmitBranchOnCondition(compiler, cond); |
| 566 } else { |
| 567 Register result = locs->out().reg(); |
| 568 Label load_true; |
| 569 EmitBranchAfterCompare(compiler, cond, &load_true); |
| 570 __ LoadObject(result, Bool::False()); |
| 571 __ b(&done); |
| 572 __ Bind(&load_true); |
| 573 __ LoadObject(result, Bool::True()); |
| 574 } |
| 575 } else { |
| 576 const int kNumberOfArguments = 2; |
| 577 const Array& kNoArgumentNames = Array::Handle(); |
| 578 compiler->GenerateStaticCall(deopt_id, |
| 579 token_pos, |
| 580 target, |
| 581 kNumberOfArguments, |
| 582 kNoArgumentNames, |
| 583 locs); |
| 584 if (branch == NULL) { |
| 585 if (kind == Token::kNE) { |
| 586 Label is_true; |
| 587 __ CompareObject(CMPRES, TMP1, V0, Bool::True()); |
| 588 __ beq(CMPRES, TMP1, &is_true); |
| 589 __ LoadObject(V0, Bool::True()); |
| 590 __ b(&done); |
| 591 __ Bind(&is_true); |
| 592 __ LoadObject(V0, Bool::False()); |
| 593 } |
| 594 } else { |
| 595 if (branch->is_checked()) { |
| 596 EmitAssertBoolean(V0, token_pos, deopt_id, locs, compiler); |
| 597 } |
| 598 __ CompareObject(CMPRES, TMP1, V0, Bool::True()); |
| 599 branch->EmitBranchOnCondition(compiler, cond); |
| 600 } |
| 601 } |
| 602 if (i < len - 1) { |
| 603 __ b(&done); |
| 604 __ Bind(&next_test); |
| 605 } |
| 606 } |
| 607 __ Bind(&done); |
| 608 } |
| 609 |
| 610 |
| 461 // Emit code when ICData's targets are all Object == (which is ===). | 611 // Emit code when ICData's targets are all Object == (which is ===). |
| 462 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, | 612 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, |
| 463 const ICData& ic_data, | 613 const ICData& ic_data, |
| 464 const LocationSummary& locs, | 614 const LocationSummary& locs, |
| 465 Token::Kind kind, | 615 Token::Kind kind, |
| 466 BranchInstr* branch, | 616 BranchInstr* branch, |
| 467 intptr_t deopt_id) { | 617 intptr_t deopt_id) { |
| 468 UNIMPLEMENTED(); | 618 UNIMPLEMENTED(); |
| 469 } | 619 } |
| 470 | 620 |
| 471 | 621 |
| 472 // First test if receiver is NULL, in which case === is applied. | 622 // First test if receiver is NULL, in which case === is applied. |
| 473 // If type feedback was provided (lists of <class-id, target>), do a | 623 // If type feedback was provided (lists of <class-id, target>), do a |
| 474 // type by type check (either === or static call to the operator. | 624 // type by type check (either === or static call to the operator. |
| 475 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 625 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 476 LocationSummary* locs, | 626 LocationSummary* locs, |
| 477 Token::Kind kind, | 627 Token::Kind kind, |
| 478 BranchInstr* branch, | 628 BranchInstr* branch, |
| 479 const ICData& ic_data, | 629 const ICData& ic_data, |
| 480 intptr_t deopt_id, | 630 intptr_t deopt_id, |
| 481 intptr_t token_pos) { | 631 intptr_t token_pos) { |
| 482 UNIMPLEMENTED(); | 632 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 483 } | 633 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 634 Register left = locs->in(0).reg(); |
| 635 Register right = locs->in(1).reg(); |
| 636 Label done, identity_compare, non_null_compare; |
| 637 __ TraceSimMsg("EmitGenericEqualityCompare"); |
| 638 __ beq(right, NULLREG, &identity_compare); |
| 639 __ bne(left, NULLREG, &non_null_compare); |
| 484 | 640 |
| 485 | 641 // Comparison with NULL is "===". |
| 486 static Condition TokenKindToSmiCondition(Token::Kind kind) { | 642 __ Bind(&identity_compare); |
| 487 switch (kind) { | 643 Condition cond = TokenKindToSmiCondition(kind); |
| 488 case Token::kEQ: return EQ; | 644 __ slt(CMPRES, left, right); |
| 489 case Token::kNE: return NE; | 645 __ slt(TMP1, right, left); |
| 490 case Token::kLT: return LT; | 646 if (branch != NULL) { |
| 491 case Token::kGT: return GT; | 647 branch->EmitBranchOnCondition(compiler, cond); |
| 492 case Token::kLTE: return LE; | 648 } else { |
| 493 case Token::kGTE: return GE; | 649 Register result = locs->out().reg(); |
| 494 default: | 650 Label load_true; |
| 495 UNREACHABLE(); | 651 EmitBranchAfterCompare(compiler, cond, &load_true); |
| 496 return VS; | 652 __ LoadObject(result, Bool::False()); |
| 653 __ b(&done); |
| 654 __ Bind(&load_true); |
| 655 __ LoadObject(result, Bool::True()); |
| 497 } | 656 } |
| 498 } | 657 __ b(&done); |
| 499 | 658 __ Bind(&non_null_compare); // Receiver is not null. |
| 500 | 659 ASSERT(left == A1); |
| 501 // Branches on condition c assuming comparison results in CMPRES and TMP1. | 660 ASSERT(right == A0); |
| 502 static void EmitBranchAfterCompare( | 661 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 503 FlowGraphCompiler* compiler, Condition c, Label* is_true) { | 662 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 504 switch (c) { | 663 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 505 case EQ: __ beq(CMPRES, TMP1, is_true); break; | 664 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, |
| 506 case NE: __ bne(CMPRES, TMP1, is_true); break; | 665 deopt_id, token_pos); |
| 507 case GT: __ bne(TMP1, ZR, is_true); break; | 666 __ Bind(&done); |
| 508 case GE: __ beq(CMPRES, ZR, is_true); break; | |
| 509 case LT: __ bne(CMPRES, ZR, is_true); break; | |
| 510 case LE: __ beq(TMP1, ZR, is_true); break; | |
| 511 default: | |
| 512 UNREACHABLE(); | |
| 513 break; | |
| 514 } | |
| 515 } | 667 } |
| 516 | 668 |
| 517 | 669 |
| 518 static Condition FlipCondition(Condition condition) { | 670 static Condition FlipCondition(Condition condition) { |
| 519 UNIMPLEMENTED(); | 671 switch (condition) { |
| 520 return condition; | 672 case EQ: return EQ; |
| 673 case NE: return NE; |
| 674 case LT: return GT; |
| 675 case LE: return GE; |
| 676 case GT: return LT; |
| 677 case GE: return LE; |
| 678 default: |
| 679 UNREACHABLE(); |
| 680 return EQ; |
| 681 } |
| 521 } | 682 } |
| 522 | 683 |
| 523 | 684 |
| 524 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 685 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 525 const LocationSummary& locs, | 686 const LocationSummary& locs, |
| 526 Token::Kind kind, | 687 Token::Kind kind, |
| 527 BranchInstr* branch) { | 688 BranchInstr* branch) { |
| 528 __ TraceSimMsg("EmitSmiComparisonOp"); | 689 __ TraceSimMsg("EmitSmiComparisonOp"); |
| 529 Location left = locs.in(0); | 690 Location left = locs.in(0); |
| 530 Location right = locs.in(1); | 691 Location right = locs.in(1); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 } | 766 } |
| 606 if (IsPolymorphic()) { | 767 if (IsPolymorphic()) { |
| 607 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), | 768 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), |
| 608 deopt_id(), token_pos()); | 769 deopt_id(), token_pos()); |
| 609 return; | 770 return; |
| 610 } | 771 } |
| 611 Register left = locs()->in(0).reg(); | 772 Register left = locs()->in(0).reg(); |
| 612 Register right = locs()->in(1).reg(); | 773 Register right = locs()->in(1).reg(); |
| 613 ASSERT(left == A1); | 774 ASSERT(left == A1); |
| 614 ASSERT(right == A0); | 775 ASSERT(right == A0); |
| 776 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 777 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 778 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 615 EmitEqualityAsInstanceCall(compiler, | 779 EmitEqualityAsInstanceCall(compiler, |
| 616 deopt_id(), | 780 deopt_id(), |
| 617 token_pos(), | 781 token_pos(), |
| 618 kind(), | 782 kind(), |
| 619 locs(), | 783 locs(), |
| 620 *ic_data()); | 784 *ic_data()); |
| 621 ASSERT(locs()->out().reg() == V0); | 785 ASSERT(locs()->out().reg() == V0); |
| 622 } | 786 } |
| 623 | 787 |
| 624 | 788 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 648 } | 812 } |
| 649 if (IsPolymorphic()) { | 813 if (IsPolymorphic()) { |
| 650 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), | 814 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), |
| 651 deopt_id(), token_pos()); | 815 deopt_id(), token_pos()); |
| 652 return; | 816 return; |
| 653 } | 817 } |
| 654 Register left = locs()->in(0).reg(); | 818 Register left = locs()->in(0).reg(); |
| 655 Register right = locs()->in(1).reg(); | 819 Register right = locs()->in(1).reg(); |
| 656 ASSERT(left == A1); | 820 ASSERT(left == A1); |
| 657 ASSERT(right == A0); | 821 ASSERT(right == A0); |
| 822 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 823 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 824 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 658 EmitEqualityAsInstanceCall(compiler, | 825 EmitEqualityAsInstanceCall(compiler, |
| 659 deopt_id(), | 826 deopt_id(), |
| 660 token_pos(), | 827 token_pos(), |
| 661 Token::kEQ, // kNE reverse occurs at branch. | 828 Token::kEQ, // kNE reverse occurs at branch. |
| 662 locs(), | 829 locs(), |
| 663 *ic_data()); | 830 *ic_data()); |
| 664 if (branch->is_checked()) { | 831 if (branch->is_checked()) { |
| 665 EmitAssertBoolean(V0, token_pos(), deopt_id(), locs(), compiler); | 832 EmitAssertBoolean(V0, token_pos(), deopt_id(), locs(), compiler); |
| 666 } | 833 } |
| 667 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; | 834 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 __ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function())); | 1013 __ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function())); |
| 847 compiler->GenerateCall(token_pos(), | 1014 compiler->GenerateCall(token_pos(), |
| 848 &StubCode::CallNativeCFunctionLabel(), | 1015 &StubCode::CallNativeCFunctionLabel(), |
| 849 PcDescriptors::kOther, | 1016 PcDescriptors::kOther, |
| 850 locs()); | 1017 locs()); |
| 851 __ Pop(result); | 1018 __ Pop(result); |
| 852 } | 1019 } |
| 853 | 1020 |
| 854 | 1021 |
| 855 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const { | 1022 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const { |
| 856 UNIMPLEMENTED(); | 1023 const intptr_t kNumInputs = 1; |
| 857 return NULL; | 1024 // TODO(fschneider): Allow immediate operands for the char code. |
| 1025 return LocationSummary::Make(kNumInputs, |
| 1026 Location::RequiresRegister(), |
| 1027 LocationSummary::kNoCall); |
| 858 } | 1028 } |
| 859 | 1029 |
| 860 | 1030 |
| 861 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1031 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 862 UNIMPLEMENTED(); | 1032 Register char_code = locs()->in(0).reg(); |
| 1033 Register result = locs()->out().reg(); |
| 1034 |
| 1035 __ TraceSimMsg("StringFromCharCodeInstr"); |
| 1036 |
| 1037 __ LoadImmediate(result, |
| 1038 reinterpret_cast<uword>(Symbols::PredefinedAddress())); |
| 1039 __ AddImmediate(result, Symbols::kNullCharCodeSymbolOffset * kWordSize); |
| 1040 __ sll(TMP1, char_code, 1); // Char code is a smi. |
| 1041 __ addu(TMP1, TMP1, result); |
| 1042 __ lw(result, Address(TMP1)); |
| 863 } | 1043 } |
| 864 | 1044 |
| 865 | 1045 |
| 866 LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const { | 1046 LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const { |
| 867 UNIMPLEMENTED(); | 1047 UNIMPLEMENTED(); |
| 868 return NULL; | 1048 return NULL; |
| 869 } | 1049 } |
| 870 | 1050 |
| 871 | 1051 |
| 872 void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1052 void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 979 if (representation() == kUnboxedDouble) { | 1159 if (representation() == kUnboxedDouble) { |
| 980 locs->set_out(Location::RequiresFpuRegister()); | 1160 locs->set_out(Location::RequiresFpuRegister()); |
| 981 } else { | 1161 } else { |
| 982 locs->set_out(Location::RequiresRegister()); | 1162 locs->set_out(Location::RequiresRegister()); |
| 983 } | 1163 } |
| 984 return locs; | 1164 return locs; |
| 985 } | 1165 } |
| 986 | 1166 |
| 987 | 1167 |
| 988 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1168 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1169 __ TraceSimMsg("LoadIndexedInstr"); |
| 989 Register array = locs()->in(0).reg(); | 1170 Register array = locs()->in(0).reg(); |
| 990 Location index = locs()->in(1); | 1171 Location index = locs()->in(1); |
| 991 | 1172 |
| 992 Address element_address(kNoRegister, 0); | 1173 Address element_address(kNoRegister, 0); |
| 993 if (IsExternal()) { | 1174 if (IsExternal()) { |
| 994 UNIMPLEMENTED(); | 1175 UNIMPLEMENTED(); |
| 995 } else { | 1176 } else { |
| 996 ASSERT(this->array()->definition()->representation() == kTagged); | 1177 ASSERT(this->array()->definition()->representation() == kTagged); |
| 997 ASSERT(index.IsRegister()); // TODO(regis): Revisit. | 1178 ASSERT(index.IsRegister()); // TODO(regis): Revisit. |
| 998 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays | 1179 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays |
| (...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 const ExternalLabel label("alloc_context", | 1919 const ExternalLabel label("alloc_context", |
| 1739 StubCode::AllocateContextEntryPoint()); | 1920 StubCode::AllocateContextEntryPoint()); |
| 1740 compiler->GenerateCall(token_pos(), | 1921 compiler->GenerateCall(token_pos(), |
| 1741 &label, | 1922 &label, |
| 1742 PcDescriptors::kOther, | 1923 PcDescriptors::kOther, |
| 1743 locs()); | 1924 locs()); |
| 1744 } | 1925 } |
| 1745 | 1926 |
| 1746 | 1927 |
| 1747 LocationSummary* CloneContextInstr::MakeLocationSummary() const { | 1928 LocationSummary* CloneContextInstr::MakeLocationSummary() const { |
| 1748 UNIMPLEMENTED(); | 1929 const intptr_t kNumInputs = 1; |
| 1749 return NULL; | 1930 const intptr_t kNumTemps = 0; |
| 1931 LocationSummary* locs = |
| 1932 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1933 locs->set_in(0, Location::RegisterLocation(T0)); |
| 1934 locs->set_out(Location::RegisterLocation(T0)); |
| 1935 return locs; |
| 1750 } | 1936 } |
| 1751 | 1937 |
| 1752 | 1938 |
| 1753 void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1939 void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1754 UNIMPLEMENTED(); | 1940 Register context_value = locs()->in(0).reg(); |
| 1941 Register result = locs()->out().reg(); |
| 1942 |
| 1943 __ TraceSimMsg("CloneContextInstr"); |
| 1944 |
| 1945 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1946 __ LoadObject(TMP1, Object::ZoneHandle()); // Make room for the result. |
| 1947 __ sw(TMP1, Address(SP, 1 * kWordSize)); |
| 1948 __ sw(context_value, Address(SP, 0 * kWordSize)); |
| 1949 |
| 1950 compiler->GenerateCallRuntime(token_pos(), |
| 1951 deopt_id(), |
| 1952 kCloneContextRuntimeEntry, |
| 1953 locs()); |
| 1954 __ lw(result, Address(SP, 1 * kWordSize)); // Get result (cloned context). |
| 1955 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1755 } | 1956 } |
| 1756 | 1957 |
| 1757 | 1958 |
| 1758 LocationSummary* CatchEntryInstr::MakeLocationSummary() const { | 1959 LocationSummary* CatchEntryInstr::MakeLocationSummary() const { |
| 1759 return LocationSummary::Make(0, | 1960 return LocationSummary::Make(0, |
| 1760 Location::NoLocation(), | 1961 Location::NoLocation(), |
| 1761 LocationSummary::kNoCall); | 1962 LocationSummary::kNoCall); |
| 1762 } | 1963 } |
| 1763 | 1964 |
| 1764 | 1965 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1843 | 2044 |
| 1844 __ LoadImmediate(TMP1, Isolate::Current()->stack_limit_address()); | 2045 __ LoadImmediate(TMP1, Isolate::Current()->stack_limit_address()); |
| 1845 | 2046 |
| 1846 __ lw(TMP1, Address(TMP1)); | 2047 __ lw(TMP1, Address(TMP1)); |
| 1847 __ BranchUnsignedLessEqual(SP, TMP1, slow_path->entry_label()); | 2048 __ BranchUnsignedLessEqual(SP, TMP1, slow_path->entry_label()); |
| 1848 | 2049 |
| 1849 __ Bind(slow_path->exit_label()); | 2050 __ Bind(slow_path->exit_label()); |
| 1850 } | 2051 } |
| 1851 | 2052 |
| 1852 | 2053 |
| 2054 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2055 BinarySmiOpInstr* shift_left) { |
| 2056 const bool is_truncating = shift_left->is_truncating(); |
| 2057 const LocationSummary& locs = *shift_left->locs(); |
| 2058 Register left = locs.in(0).reg(); |
| 2059 Register result = locs.out().reg(); |
| 2060 Label* deopt = shift_left->CanDeoptimize() ? |
| 2061 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; |
| 2062 |
| 2063 __ TraceSimMsg("EmitSmiShiftLeft"); |
| 2064 |
| 2065 if (locs.in(1).IsConstant()) { |
| 2066 const Object& constant = locs.in(1).constant(); |
| 2067 ASSERT(constant.IsSmi()); |
| 2068 // Immediate shift operation takes 5 bits for the count. |
| 2069 const intptr_t kCountLimit = 0x1F; |
| 2070 const intptr_t value = Smi::Cast(constant).Value(); |
| 2071 if (value == 0) { |
| 2072 // No code needed. |
| 2073 } else if ((value < 0) || (value >= kCountLimit)) { |
| 2074 // This condition may not be known earlier in some cases because |
| 2075 // of constant propagation, inlining, etc. |
| 2076 if ((value >= kCountLimit) && is_truncating) { |
| 2077 __ mov(result, ZR); |
| 2078 } else { |
| 2079 // Result is Mint or exception. |
| 2080 __ b(deopt); |
| 2081 } |
| 2082 } else { |
| 2083 if (!is_truncating) { |
| 2084 // Check for overflow (preserve left). |
| 2085 __ sll(TMP1, left, value); |
| 2086 __ sra(TMP1, TMP1, value); |
| 2087 __ bne(TMP1, left, deopt); // Overflow. |
| 2088 } |
| 2089 // Shift for result now we know there is no overflow. |
| 2090 __ sll(result, left, value); |
| 2091 } |
| 2092 return; |
| 2093 } |
| 2094 |
| 2095 // Right (locs.in(1)) is not constant. |
| 2096 Register right = locs.in(1).reg(); |
| 2097 Range* right_range = shift_left->right()->definition()->range(); |
| 2098 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 2099 // TODO(srdjan): Implement code below for is_truncating(). |
| 2100 // If left is constant, we know the maximal allowed size for right. |
| 2101 const Object& obj = shift_left->left()->BoundConstant(); |
| 2102 if (obj.IsSmi()) { |
| 2103 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2104 if (left_int == 0) { |
| 2105 __ bltz(right, deopt); |
| 2106 return; |
| 2107 } |
| 2108 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2109 const bool right_needs_check = |
| 2110 (right_range == NULL) || |
| 2111 !right_range->IsWithin(0, max_right - 1); |
| 2112 if (right_needs_check) { |
| 2113 __ BranchUnsignedGreaterEqual( |
| 2114 right, reinterpret_cast<int32_t>(Smi::New(max_right)), deopt); |
| 2115 } |
| 2116 __ SmiUntag(right); |
| 2117 __ sllv(result, left, right); |
| 2118 } |
| 2119 return; |
| 2120 } |
| 2121 |
| 2122 const bool right_needs_check = |
| 2123 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2124 if (is_truncating) { |
| 2125 if (right_needs_check) { |
| 2126 const bool right_may_be_negative = |
| 2127 (right_range == NULL) || |
| 2128 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 2129 if (right_may_be_negative) { |
| 2130 ASSERT(shift_left->CanDeoptimize()); |
| 2131 __ bltz(right, deopt); |
| 2132 } |
| 2133 Label done, is_not_zero; |
| 2134 |
| 2135 __ sltiu(CMPRES, |
| 2136 right, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 2137 __ movz(result, ZR, CMPRES); // result = right >= kBits ? 0 : result. |
| 2138 __ mov(TMP1, right); |
| 2139 __ SmiUntag(TMP1); |
| 2140 __ sllv(TMP1, left, TMP1); |
| 2141 // result = right < kBits ? left << right : result. |
| 2142 __ movn(result, TMP1, CMPRES); |
| 2143 } else { |
| 2144 __ SmiUntag(right); |
| 2145 __ sllv(result, left, right); |
| 2146 } |
| 2147 } else { |
| 2148 if (right_needs_check) { |
| 2149 ASSERT(shift_left->CanDeoptimize()); |
| 2150 __ BranchUnsignedGreaterEqual( |
| 2151 right, reinterpret_cast<int32_t>(Smi::New(Smi::kBits)), deopt); |
| 2152 } |
| 2153 // Left is not a constant. |
| 2154 // Check if count too large for handling it inlined. |
| 2155 __ SmiUntag(right); |
| 2156 // Overflow test (preserve left and right); |
| 2157 __ sllv(TMP1, left, right); |
| 2158 __ srav(TMP1, TMP1, right); |
| 2159 __ bne(TMP1, left, deopt); // Overflow. |
| 2160 // Shift for result now we know there is no overflow. |
| 2161 __ sllv(result, left, right); |
| 2162 } |
| 2163 } |
| 2164 |
| 2165 |
| 1853 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2166 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 1854 const intptr_t kNumInputs = 2; | 2167 const intptr_t kNumInputs = 2; |
| 1855 if (op_kind() == Token::kTRUNCDIV) { | 2168 if (op_kind() == Token::kTRUNCDIV) { |
| 1856 UNIMPLEMENTED(); | 2169 UNIMPLEMENTED(); |
| 1857 return NULL; | 2170 return NULL; |
| 1858 } else { | 2171 } else { |
| 1859 const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0; | 2172 const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0; |
| 1860 LocationSummary* summary = | 2173 LocationSummary* summary = |
| 1861 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2174 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1862 summary->set_in(0, Location::RequiresRegister()); | 2175 summary->set_in(0, Location::RequiresRegister()); |
| 1863 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2176 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 1864 if (op_kind() == Token::kADD) { | 2177 if (op_kind() == Token::kADD) { |
| 1865 // Need an extra temp for the overflow detection code. | 2178 // Need an extra temp for the overflow detection code. |
| 1866 summary->set_temp(0, Location::RequiresRegister()); | 2179 summary->set_temp(0, Location::RequiresRegister()); |
| 1867 } | 2180 } |
| 1868 // We make use of 3-operand instructions by not requiring result register | 2181 // We make use of 3-operand instructions by not requiring result register |
| 1869 // to be identical to first input register as on Intel. | 2182 // to be identical to first input register as on Intel. |
| 1870 summary->set_out(Location::RequiresRegister()); | 2183 summary->set_out(Location::RequiresRegister()); |
| 1871 return summary; | 2184 return summary; |
| 1872 } | 2185 } |
| 1873 } | 2186 } |
| 1874 | 2187 |
| 1875 | 2188 |
| 1876 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2189 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1877 __ TraceSimMsg("BinarySmiOpInstr"); | 2190 __ TraceSimMsg("BinarySmiOpInstr"); |
| 1878 if (op_kind() == Token::kSHL) { | 2191 if (op_kind() == Token::kSHL) { |
| 1879 UNIMPLEMENTED(); | 2192 EmitSmiShiftLeft(compiler, this); |
| 1880 return; | 2193 return; |
| 1881 } | 2194 } |
| 1882 | 2195 |
| 1883 ASSERT(!is_truncating()); | 2196 ASSERT(!is_truncating()); |
| 1884 Register left = locs()->in(0).reg(); | 2197 Register left = locs()->in(0).reg(); |
| 1885 Register result = locs()->out().reg(); | 2198 Register result = locs()->out().reg(); |
| 1886 Label* deopt = NULL; | 2199 Label* deopt = NULL; |
| 1887 if (CanDeoptimize()) { | 2200 if (CanDeoptimize()) { |
| 1888 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); | 2201 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
| 1889 } | 2202 } |
| 1890 | 2203 |
| 1891 if (locs()->in(1).IsConstant()) { | 2204 if (locs()->in(1).IsConstant()) { |
| 1892 const Object& constant = locs()->in(1).constant(); | 2205 const Object& constant = locs()->in(1).constant(); |
| 1893 ASSERT(constant.IsSmi()); | 2206 ASSERT(constant.IsSmi()); |
| 1894 int32_t imm = reinterpret_cast<int32_t>(constant.raw()); | 2207 int32_t imm = reinterpret_cast<int32_t>(constant.raw()); |
| 1895 switch (op_kind()) { | 2208 switch (op_kind()) { |
| 1896 case Token::kSUB: { | 2209 case Token::kSUB: { |
| 2210 __ TraceSimMsg("kSUB imm"); |
| 1897 if (deopt == NULL) { | 2211 if (deopt == NULL) { |
| 1898 __ AddImmediate(result, left, -imm); | 2212 __ AddImmediate(result, left, -imm); |
| 1899 } else { | 2213 } else { |
| 1900 __ SubImmediateDetectOverflow(result, left, imm, CMPRES); | 2214 __ SubImmediateDetectOverflow(result, left, imm, CMPRES); |
| 1901 __ bltz(CMPRES, deopt); | 2215 __ bltz(CMPRES, deopt); |
| 1902 } | 2216 } |
| 1903 break; | 2217 break; |
| 1904 } | 2218 } |
| 1905 case Token::kADD: { | 2219 case Token::kADD: { |
| 1906 if (deopt == NULL) { | 2220 if (deopt == NULL) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1966 // No overflow check. | 2280 // No overflow check. |
| 1967 if (Utils::IsUint(kImmBits, imm)) { | 2281 if (Utils::IsUint(kImmBits, imm)) { |
| 1968 __ xori(result, left, Immediate(imm)); | 2282 __ xori(result, left, Immediate(imm)); |
| 1969 } else { | 2283 } else { |
| 1970 __ LoadImmediate(TMP1, imm); | 2284 __ LoadImmediate(TMP1, imm); |
| 1971 __ xor_(result, left, TMP1); | 2285 __ xor_(result, left, TMP1); |
| 1972 } | 2286 } |
| 1973 break; | 2287 break; |
| 1974 } | 2288 } |
| 1975 case Token::kSHR: { | 2289 case Token::kSHR: { |
| 1976 UNIMPLEMENTED(); | 2290 // sarl operation masks the count to 5 bits. |
| 2291 const intptr_t kCountLimit = 0x1F; |
| 2292 intptr_t value = Smi::Cast(constant).Value(); |
| 2293 |
| 2294 __ TraceSimMsg("kSHR"); |
| 2295 |
| 2296 if (value == 0) { |
| 2297 // TODO(vegorov): should be handled outside. |
| 2298 __ break_(0); |
| 2299 break; |
| 2300 } else if (value < 0) { |
| 2301 // TODO(vegorov): should be handled outside. |
| 2302 __ b(deopt); |
| 2303 break; |
| 2304 } |
| 2305 |
| 2306 value = value + kSmiTagSize; |
| 2307 if (value >= kCountLimit) value = kCountLimit; |
| 2308 |
| 2309 __ sra(result, left, value); |
| 2310 __ SmiTag(result); |
| 1977 break; | 2311 break; |
| 1978 } | 2312 } |
| 1979 | 2313 |
| 1980 default: | 2314 default: |
| 1981 UNREACHABLE(); | 2315 UNREACHABLE(); |
| 1982 break; | 2316 break; |
| 1983 } | 2317 } |
| 1984 return; | 2318 return; |
| 1985 } | 2319 } |
| 1986 | 2320 |
| 1987 Register right = locs()->in(1).reg(); | 2321 Register right = locs()->in(1).reg(); |
| 1988 switch (op_kind()) { | 2322 switch (op_kind()) { |
| 1989 case Token::kADD: { | 2323 case Token::kADD: { |
| 1990 if (deopt == NULL) { | 2324 if (deopt == NULL) { |
| 1991 __ addu(result, left, right); | 2325 __ addu(result, left, right); |
| 1992 } else { | 2326 } else { |
| 1993 Register temp = locs()->temp(0).reg(); | 2327 Register temp = locs()->temp(0).reg(); |
| 1994 __ AdduDetectOverflow(result, left, right, CMPRES, temp); | 2328 __ AdduDetectOverflow(result, left, right, CMPRES, temp); |
| 1995 __ bltz(CMPRES, deopt); | 2329 __ bltz(CMPRES, deopt); |
| 1996 } | 2330 } |
| 1997 break; | 2331 break; |
| 1998 } | 2332 } |
| 1999 case Token::kSUB: { | 2333 case Token::kSUB: { |
| 2334 __ TraceSimMsg("kSUB"); |
| 2000 if (deopt == NULL) { | 2335 if (deopt == NULL) { |
| 2001 __ subu(result, left, right); | 2336 __ subu(result, left, right); |
| 2002 } else { | 2337 } else { |
| 2003 __ SubuDetectOverflow(result, left, right, CMPRES); | 2338 __ SubuDetectOverflow(result, left, right, CMPRES); |
| 2004 __ bltz(CMPRES, deopt); | 2339 __ bltz(CMPRES, deopt); |
| 2005 } | 2340 } |
| 2006 break; | 2341 break; |
| 2007 } | 2342 } |
| 2008 case Token::kMUL: { | 2343 case Token::kMUL: { |
| 2344 __ TraceSimMsg("kMUL"); |
| 2009 __ SmiUntag(left); | 2345 __ SmiUntag(left); |
| 2010 __ mult(left, right); | 2346 __ mult(left, right); |
| 2011 __ mflo(result); | 2347 __ mflo(result); |
| 2012 if (deopt != NULL) { | 2348 if (deopt != NULL) { |
| 2013 UNIMPLEMENTED(); | 2349 __ mfhi(TMP1); |
| 2350 __ sra(CMPRES, result, 31); |
| 2351 __ bne(TMP1, CMPRES, deopt); |
| 2014 } | 2352 } |
| 2015 break; | 2353 break; |
| 2016 } | 2354 } |
| 2017 case Token::kBIT_AND: { | 2355 case Token::kBIT_AND: { |
| 2018 // No overflow check. | 2356 // No overflow check. |
| 2019 __ and_(result, left, right); | 2357 __ and_(result, left, right); |
| 2020 break; | 2358 break; |
| 2021 } | 2359 } |
| 2022 case Token::kBIT_OR: { | 2360 case Token::kBIT_OR: { |
| 2023 // No overflow check. | 2361 // No overflow check. |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2435 UNIMPLEMENTED(); | 2773 UNIMPLEMENTED(); |
| 2436 } | 2774 } |
| 2437 | 2775 |
| 2438 | 2776 |
| 2439 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { | 2777 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { |
| 2440 return MakeCallSummary(); | 2778 return MakeCallSummary(); |
| 2441 } | 2779 } |
| 2442 | 2780 |
| 2443 | 2781 |
| 2444 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2782 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2445 __ TraceSimMsg("PolymorphicInstanceCallInstr"); | |
| 2446 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 2783 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2447 kDeoptPolymorphicInstanceCallTestFail); | 2784 kDeoptPolymorphicInstanceCallTestFail); |
| 2785 __ TraceSimMsg("PolymorphicInstanceCallInstr"); |
| 2448 if (ic_data().NumberOfChecks() == 0) { | 2786 if (ic_data().NumberOfChecks() == 0) { |
| 2449 __ b(deopt); | 2787 __ b(deopt); |
| 2450 return; | 2788 return; |
| 2451 } | 2789 } |
| 2452 ASSERT(ic_data().num_args_tested() == 1); | 2790 ASSERT(ic_data().num_args_tested() == 1); |
| 2453 if (!with_checks()) { | 2791 if (!with_checks()) { |
| 2454 ASSERT(ic_data().HasOneTarget()); | 2792 ASSERT(ic_data().HasOneTarget()); |
| 2455 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); | 2793 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| 2456 compiler->GenerateStaticCall(deopt_id(), | 2794 compiler->GenerateStaticCall(deopt_id(), |
| 2457 instance_call()->token_pos(), | 2795 instance_call()->token_pos(), |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2819 } else { | 3157 } else { |
| 2820 compiler->EmitEqualityRegRegCompare(left.reg(), | 3158 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 2821 right.reg(), | 3159 right.reg(), |
| 2822 needs_number_check(), | 3160 needs_number_check(), |
| 2823 token_pos()); | 3161 token_pos()); |
| 2824 } | 3162 } |
| 2825 | 3163 |
| 2826 Register result = locs()->out().reg(); | 3164 Register result = locs()->out().reg(); |
| 2827 Label load_true, done; | 3165 Label load_true, done; |
| 2828 if (kind() == Token::kEQ_STRICT) { | 3166 if (kind() == Token::kEQ_STRICT) { |
| 2829 __ beq(CMPRES, ZR, &load_true); | 3167 __ beq(CMPRES, TMP1, &load_true); |
| 2830 } else { | 3168 } else { |
| 2831 ASSERT(kind() == Token::kNE_STRICT); | 3169 ASSERT(kind() == Token::kNE_STRICT); |
| 2832 __ bne(CMPRES, ZR, &load_true); | 3170 __ bne(CMPRES, TMP1, &load_true); |
| 2833 } | 3171 } |
| 2834 __ LoadObject(result, Bool::False()); | 3172 __ LoadObject(result, Bool::False()); |
| 2835 __ b(&done); | 3173 __ b(&done); |
| 2836 __ Bind(&load_true); | 3174 __ Bind(&load_true); |
| 2837 __ LoadObject(result, Bool::True()); | 3175 __ LoadObject(result, Bool::True()); |
| 2838 __ Bind(&done); | 3176 __ Bind(&done); |
| 2839 } | 3177 } |
| 2840 | 3178 |
| 2841 | 3179 |
| 2842 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 3180 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2970 compiler->GenerateCall(token_pos(), | 3308 compiler->GenerateCall(token_pos(), |
| 2971 &label, | 3309 &label, |
| 2972 PcDescriptors::kOther, | 3310 PcDescriptors::kOther, |
| 2973 locs()); | 3311 locs()); |
| 2974 __ Drop(2); // Discard type arguments and receiver. | 3312 __ Drop(2); // Discard type arguments and receiver. |
| 2975 } | 3313 } |
| 2976 | 3314 |
| 2977 } // namespace dart | 3315 } // namespace dart |
| 2978 | 3316 |
| 2979 #endif // defined TARGET_ARCH_MIPS | 3317 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |