| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 case LS: return HI; | 121 case LS: return HI; |
| 122 case HI: return LS; | 122 case HI: return LS; |
| 123 case CS: return CC; | 123 case CS: return CC; |
| 124 default: | 124 default: |
| 125 UNREACHABLE(); | 125 UNREACHABLE(); |
| 126 return EQ; | 126 return EQ; |
| 127 } | 127 } |
| 128 } | 128 } |
| 129 | 129 |
| 130 | 130 |
| 131 static bool BindsToSmiConstant(Value* val, intptr_t* smi_value) { | |
| 132 if (!val->BindsToConstant()) { | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 const Object& bound_constant = val->BoundConstant(); | |
| 137 if (!bound_constant.IsSmi()) { | |
| 138 return false; | |
| 139 } | |
| 140 | |
| 141 *smi_value = Smi::Cast(bound_constant).Value(); | |
| 142 return true; | |
| 143 } | |
| 144 | |
| 145 | |
| 146 // Detect pattern when one value is zero and another is a power of 2. | 131 // Detect pattern when one value is zero and another is a power of 2. |
| 147 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { | 132 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { |
| 148 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || | 133 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || |
| 149 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); | 134 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); |
| 150 } | 135 } |
| 151 | 136 |
| 152 | 137 |
| 153 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | |
| 154 Value* v1, | |
| 155 Value* v2) { | |
| 156 if (!(comparison->IsStrictCompare() && | |
| 157 !comparison->AsStrictCompare()->needs_number_check()) && | |
| 158 !(comparison->IsEqualityCompare() && | |
| 159 (comparison->AsEqualityCompare()->operation_cid() == kSmiCid))) { | |
| 160 return false; | |
| 161 } | |
| 162 | |
| 163 intptr_t v1_value, v2_value; | |
| 164 | |
| 165 if (!BindsToSmiConstant(v1, &v1_value) || | |
| 166 !BindsToSmiConstant(v2, &v2_value)) { | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 return true; | |
| 171 } | |
| 172 | |
| 173 | |
| 174 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { | 138 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { |
| 175 const intptr_t kNumInputs = 2; | 139 const intptr_t kNumInputs = 2; |
| 176 const intptr_t kNumTemps = 0; | 140 const intptr_t kNumTemps = 0; |
| 177 LocationSummary* locs = | 141 LocationSummary* locs = |
| 178 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 142 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 179 locs->set_in(0, Location::RegisterOrConstant(left())); | 143 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 180 locs->set_in(1, Location::RegisterOrConstant(right())); | 144 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 181 locs->set_out(Location::RequiresRegister()); | 145 locs->set_out(Location::RequiresRegister()); |
| 182 return locs; | 146 return locs; |
| 183 } | 147 } |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 case LS: return CS; | 440 case LS: return CS; |
| 477 case HI: return CC; | 441 case HI: return CC; |
| 478 case CS: return LS; | 442 case CS: return LS; |
| 479 default: | 443 default: |
| 480 UNREACHABLE(); | 444 UNREACHABLE(); |
| 481 return EQ; | 445 return EQ; |
| 482 } | 446 } |
| 483 } | 447 } |
| 484 | 448 |
| 485 | 449 |
| 450 static void EmitBranchOnValue(FlowGraphCompiler* compiler, |
| 451 TargetEntryInstr* true_successor, |
| 452 TargetEntryInstr* false_successor, |
| 453 bool value) { |
| 454 if (value && !compiler->CanFallThroughTo(true_successor)) { |
| 455 __ b(compiler->GetJumpLabel(true_successor)); |
| 456 } else if (!value && !compiler->CanFallThroughTo(false_successor)) { |
| 457 __ b(compiler->GetJumpLabel(false_successor)); |
| 458 } |
| 459 } |
| 460 |
| 461 |
| 462 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 463 TargetEntryInstr* true_successor, |
| 464 TargetEntryInstr* false_successor, |
| 465 Condition true_condition) { |
| 466 if (compiler->CanFallThroughTo(false_successor)) { |
| 467 // If the next block is the false successor we will fall through to it. |
| 468 __ b(compiler->GetJumpLabel(true_successor), true_condition); |
| 469 } else { |
| 470 // If the next block is not the false successor we will branch to it. |
| 471 Condition false_condition = NegateCondition(true_condition); |
| 472 __ b(compiler->GetJumpLabel(false_successor), false_condition); |
| 473 |
| 474 // Fall through or jump to the true successor. |
| 475 if (!compiler->CanFallThroughTo(true_successor)) { |
| 476 __ b(compiler->GetJumpLabel(true_successor)); |
| 477 } |
| 478 } |
| 479 } |
| 480 |
| 481 |
| 486 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 482 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 487 const LocationSummary& locs, | 483 const LocationSummary& locs, |
| 488 Token::Kind kind, | 484 Token::Kind kind, |
| 489 BranchInstr* branch) { | 485 BranchInstr* branch) { |
| 490 Location left = locs.in(0); | 486 Location left = locs.in(0); |
| 491 Location right = locs.in(1); | 487 Location right = locs.in(1); |
| 492 ASSERT(!left.IsConstant() || !right.IsConstant()); | 488 ASSERT(!left.IsConstant() || !right.IsConstant()); |
| 493 | 489 |
| 494 Condition true_condition = TokenKindToSmiCondition(kind); | 490 Condition true_condition = TokenKindToSmiCondition(kind); |
| 495 | 491 |
| 496 if (left.IsConstant()) { | 492 if (left.IsConstant()) { |
| 497 __ CompareObject(right.reg(), left.constant()); | 493 __ CompareObject(right.reg(), left.constant()); |
| 498 true_condition = FlipCondition(true_condition); | 494 true_condition = FlipCondition(true_condition); |
| 499 } else if (right.IsConstant()) { | 495 } else if (right.IsConstant()) { |
| 500 __ CompareObject(left.reg(), right.constant()); | 496 __ CompareObject(left.reg(), right.constant()); |
| 501 } else { | 497 } else { |
| 502 __ cmp(left.reg(), ShifterOperand(right.reg())); | 498 __ cmp(left.reg(), ShifterOperand(right.reg())); |
| 503 } | 499 } |
| 504 | 500 |
| 505 if (branch != NULL) { | 501 if (branch != NULL) { |
| 506 branch->EmitBranchOnCondition(compiler, true_condition); | 502 EmitBranchOnCondition(compiler, |
| 503 branch->true_successor(), |
| 504 branch->false_successor(), |
| 505 true_condition); |
| 507 } else { | 506 } else { |
| 508 Register result = locs.out().reg(); | 507 Register result = locs.out().reg(); |
| 509 __ LoadObject(result, Bool::True(), true_condition); | 508 __ LoadObject(result, Bool::True(), true_condition); |
| 510 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); | 509 __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); |
| 511 } | 510 } |
| 512 } | 511 } |
| 513 | 512 |
| 514 | 513 |
| 515 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | 514 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| 516 const LocationSummary& locs, | 515 const LocationSummary& locs, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 536 case Token::kGT: return GT; | 535 case Token::kGT: return GT; |
| 537 case Token::kLTE: return LE; | 536 case Token::kLTE: return LE; |
| 538 case Token::kGTE: return GE; | 537 case Token::kGTE: return GE; |
| 539 default: | 538 default: |
| 540 UNREACHABLE(); | 539 UNREACHABLE(); |
| 541 return VS; | 540 return VS; |
| 542 } | 541 } |
| 543 } | 542 } |
| 544 | 543 |
| 545 | 544 |
| 545 static void EmitDoubleCompareBranch(FlowGraphCompiler* compiler, |
| 546 Condition true_condition, |
| 547 FpuRegister left, |
| 548 FpuRegister right, |
| 549 BranchInstr* branch) { |
| 550 ASSERT(branch != NULL); |
| 551 DRegister dleft = EvenDRegisterOf(left); |
| 552 DRegister dright = EvenDRegisterOf(right); |
| 553 __ vcmpd(dleft, dright); |
| 554 __ vmstat(); |
| 555 BlockEntryInstr* nan_result = (true_condition == NE) ? |
| 556 branch->true_successor() : branch->false_successor(); |
| 557 __ b(compiler->GetJumpLabel(nan_result), VS); |
| 558 EmitBranchOnCondition(compiler, |
| 559 branch->true_successor(), |
| 560 branch->false_successor(), |
| 561 true_condition); |
| 562 } |
| 563 |
| 564 |
| 565 static void EmitDoubleCompareBool(FlowGraphCompiler* compiler, |
| 566 Condition true_condition, |
| 567 FpuRegister left, |
| 568 FpuRegister right, |
| 569 Register result) { |
| 570 DRegister dleft = EvenDRegisterOf(left); |
| 571 DRegister dright = EvenDRegisterOf(right); |
| 572 __ vcmpd(dleft, dright); |
| 573 __ vmstat(); |
| 574 __ LoadObject(result, Bool::False()); |
| 575 Label done; |
| 576 if (true_condition != NE) { |
| 577 __ b(&done, VS); // x == NaN -> false, x != NaN -> true. |
| 578 } |
| 579 __ LoadObject(result, Bool::True(), true_condition); |
| 580 __ Bind(&done); |
| 581 } |
| 582 |
| 583 |
| 546 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 584 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 547 const LocationSummary& locs, | 585 const LocationSummary& locs, |
| 548 Token::Kind kind, | 586 Token::Kind kind, |
| 549 BranchInstr* branch) { | 587 BranchInstr* branch) { |
| 550 QRegister left = locs.in(0).fpu_reg(); | 588 QRegister left = locs.in(0).fpu_reg(); |
| 551 QRegister right = locs.in(1).fpu_reg(); | 589 QRegister right = locs.in(1).fpu_reg(); |
| 552 | 590 |
| 553 Condition true_condition = TokenKindToDoubleCondition(kind); | 591 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 554 if (branch != NULL) { | 592 if (branch != NULL) { |
| 555 compiler->EmitDoubleCompareBranch( | 593 EmitDoubleCompareBranch(compiler, true_condition, left, right, branch); |
| 556 true_condition, left, right, branch); | |
| 557 } else { | 594 } else { |
| 558 compiler->EmitDoubleCompareBool( | 595 EmitDoubleCompareBool(compiler, true_condition, |
| 559 true_condition, left, right, locs.out().reg()); | 596 left, right, locs.out().reg()); |
| 560 } | 597 } |
| 561 } | 598 } |
| 562 | 599 |
| 563 | 600 |
| 564 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 601 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 565 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 602 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 566 BranchInstr* kNoBranch = NULL; | 603 BranchInstr* kNoBranch = NULL; |
| 567 if (operation_cid() == kSmiCid) { | 604 if (operation_cid() == kSmiCid) { |
| 568 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); | 605 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); |
| 569 return; | 606 return; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 Register left = locs()->in(0).reg(); | 662 Register left = locs()->in(0).reg(); |
| 626 Location right = locs()->in(1); | 663 Location right = locs()->in(1); |
| 627 if (right.IsConstant()) { | 664 if (right.IsConstant()) { |
| 628 ASSERT(right.constant().IsSmi()); | 665 ASSERT(right.constant().IsSmi()); |
| 629 const int32_t imm = | 666 const int32_t imm = |
| 630 reinterpret_cast<int32_t>(right.constant().raw()); | 667 reinterpret_cast<int32_t>(right.constant().raw()); |
| 631 __ TestImmediate(left, imm); | 668 __ TestImmediate(left, imm); |
| 632 } else { | 669 } else { |
| 633 __ tst(left, ShifterOperand(right.reg())); | 670 __ tst(left, ShifterOperand(right.reg())); |
| 634 } | 671 } |
| 635 branch->EmitBranchOnCondition(compiler, branch_condition); | 672 EmitBranchOnCondition(compiler, |
| 673 branch->true_successor(), |
| 674 branch->false_successor(), |
| 675 branch_condition); |
| 636 } | 676 } |
| 637 | 677 |
| 638 | 678 |
| 639 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 679 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 640 const intptr_t kNumInputs = 2; | 680 const intptr_t kNumInputs = 2; |
| 641 const intptr_t kNumTemps = 0; | 681 const intptr_t kNumTemps = 0; |
| 642 if (operation_cid() == kMintCid) { | 682 if (operation_cid() == kMintCid) { |
| 643 const intptr_t kNumTemps = 2; | 683 const intptr_t kNumTemps = 2; |
| 644 LocationSummary* locs = | 684 LocationSummary* locs = |
| 645 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 685 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| (...skipping 3728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4374 } | 4414 } |
| 4375 | 4415 |
| 4376 // We can fall through if the successor is the next block in the list. | 4416 // We can fall through if the successor is the next block in the list. |
| 4377 // Otherwise, we need a jump. | 4417 // Otherwise, we need a jump. |
| 4378 if (!compiler->CanFallThroughTo(successor())) { | 4418 if (!compiler->CanFallThroughTo(successor())) { |
| 4379 __ b(compiler->GetJumpLabel(successor())); | 4419 __ b(compiler->GetJumpLabel(successor())); |
| 4380 } | 4420 } |
| 4381 } | 4421 } |
| 4382 | 4422 |
| 4383 | 4423 |
| 4384 void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, | |
| 4385 bool value) { | |
| 4386 if (value && !compiler->CanFallThroughTo(true_successor())) { | |
| 4387 __ b(compiler->GetJumpLabel(true_successor())); | |
| 4388 } else if (!value && !compiler->CanFallThroughTo(false_successor())) { | |
| 4389 __ b(compiler->GetJumpLabel(false_successor())); | |
| 4390 } | |
| 4391 } | |
| 4392 | |
| 4393 | |
| 4394 void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler, | |
| 4395 Condition true_condition) { | |
| 4396 if (compiler->CanFallThroughTo(false_successor())) { | |
| 4397 // If the next block is the false successor we will fall through to it. | |
| 4398 __ b(compiler->GetJumpLabel(true_successor()), true_condition); | |
| 4399 } else { | |
| 4400 // If the next block is not the false successor we will branch to it. | |
| 4401 Condition false_condition = NegateCondition(true_condition); | |
| 4402 __ b(compiler->GetJumpLabel(false_successor()), false_condition); | |
| 4403 | |
| 4404 // Fall through or jump to the true successor. | |
| 4405 if (!compiler->CanFallThroughTo(true_successor())) { | |
| 4406 __ b(compiler->GetJumpLabel(true_successor())); | |
| 4407 } | |
| 4408 } | |
| 4409 } | |
| 4410 | |
| 4411 | |
| 4412 LocationSummary* CurrentContextInstr::MakeLocationSummary() const { | 4424 LocationSummary* CurrentContextInstr::MakeLocationSummary() const { |
| 4413 return LocationSummary::Make(0, | 4425 return LocationSummary::Make(0, |
| 4414 Location::RequiresRegister(), | 4426 Location::RequiresRegister(), |
| 4415 LocationSummary::kNoCall); | 4427 LocationSummary::kNoCall); |
| 4416 } | 4428 } |
| 4417 | 4429 |
| 4418 | 4430 |
| 4419 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4431 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 4420 __ mov(locs()->out().reg(), ShifterOperand(CTX)); | 4432 __ mov(locs()->out().reg(), ShifterOperand(CTX)); |
| 4421 } | 4433 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4473 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 4485 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 4474 BranchInstr* branch) { | 4486 BranchInstr* branch) { |
| 4475 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); | 4487 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 4476 Location left = locs()->in(0); | 4488 Location left = locs()->in(0); |
| 4477 Location right = locs()->in(1); | 4489 Location right = locs()->in(1); |
| 4478 if (left.IsConstant() && right.IsConstant()) { | 4490 if (left.IsConstant() && right.IsConstant()) { |
| 4479 // TODO(vegorov): should be eliminated earlier by constant propagation. | 4491 // TODO(vegorov): should be eliminated earlier by constant propagation. |
| 4480 const bool result = (kind() == Token::kEQ_STRICT) ? | 4492 const bool result = (kind() == Token::kEQ_STRICT) ? |
| 4481 left.constant().raw() == right.constant().raw() : | 4493 left.constant().raw() == right.constant().raw() : |
| 4482 left.constant().raw() != right.constant().raw(); | 4494 left.constant().raw() != right.constant().raw(); |
| 4483 branch->EmitBranchOnValue(compiler, result); | 4495 EmitBranchOnValue(compiler, |
| 4496 branch->true_successor(), |
| 4497 branch->false_successor(), |
| 4498 result); |
| 4484 return; | 4499 return; |
| 4485 } | 4500 } |
| 4486 if (left.IsConstant()) { | 4501 if (left.IsConstant()) { |
| 4487 compiler->EmitEqualityRegConstCompare(right.reg(), | 4502 compiler->EmitEqualityRegConstCompare(right.reg(), |
| 4488 left.constant(), | 4503 left.constant(), |
| 4489 needs_number_check(), | 4504 needs_number_check(), |
| 4490 token_pos()); | 4505 token_pos()); |
| 4491 } else if (right.IsConstant()) { | 4506 } else if (right.IsConstant()) { |
| 4492 compiler->EmitEqualityRegConstCompare(left.reg(), | 4507 compiler->EmitEqualityRegConstCompare(left.reg(), |
| 4493 right.constant(), | 4508 right.constant(), |
| 4494 needs_number_check(), | 4509 needs_number_check(), |
| 4495 token_pos()); | 4510 token_pos()); |
| 4496 } else { | 4511 } else { |
| 4497 compiler->EmitEqualityRegRegCompare(left.reg(), | 4512 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 4498 right.reg(), | 4513 right.reg(), |
| 4499 needs_number_check(), | 4514 needs_number_check(), |
| 4500 token_pos()); | 4515 token_pos()); |
| 4501 } | 4516 } |
| 4502 | 4517 |
| 4503 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE; | 4518 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE; |
| 4504 branch->EmitBranchOnCondition(compiler, true_condition); | 4519 EmitBranchOnCondition(compiler, |
| 4520 branch->true_successor(), |
| 4521 branch->false_successor(), |
| 4522 true_condition); |
| 4505 } | 4523 } |
| 4506 | 4524 |
| 4507 | 4525 |
| 4508 LocationSummary* BooleanNegateInstr::MakeLocationSummary() const { | 4526 LocationSummary* BooleanNegateInstr::MakeLocationSummary() const { |
| 4509 return LocationSummary::Make(1, | 4527 return LocationSummary::Make(1, |
| 4510 Location::RequiresRegister(), | 4528 Location::RequiresRegister(), |
| 4511 LocationSummary::kNoCall); | 4529 LocationSummary::kNoCall); |
| 4512 } | 4530 } |
| 4513 | 4531 |
| 4514 | 4532 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4578 compiler->GenerateCall(token_pos(), | 4596 compiler->GenerateCall(token_pos(), |
| 4579 &label, | 4597 &label, |
| 4580 PcDescriptors::kOther, | 4598 PcDescriptors::kOther, |
| 4581 locs()); | 4599 locs()); |
| 4582 __ Drop(2); // Discard type arguments and receiver. | 4600 __ Drop(2); // Discard type arguments and receiver. |
| 4583 } | 4601 } |
| 4584 | 4602 |
| 4585 } // namespace dart | 4603 } // namespace dart |
| 4586 | 4604 |
| 4587 #endif // defined TARGET_ARCH_ARM | 4605 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |