| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 __ CompareImmediate(R2, fp_sp_dist, PP); | 90 __ CompareImmediate(R2, fp_sp_dist, PP); |
| 91 __ b(&stack_ok, EQ); | 91 __ b(&stack_ok, EQ); |
| 92 __ hlt(0); | 92 __ hlt(0); |
| 93 __ Bind(&stack_ok); | 93 __ Bind(&stack_ok); |
| 94 #endif | 94 #endif |
| 95 __ LeaveDartFrame(); | 95 __ LeaveDartFrame(); |
| 96 __ ret(); | 96 __ ret(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 | 99 |
| 100 static Condition NegateCondition(Condition condition) { |
| 101 switch (condition) { |
| 102 case EQ: return NE; |
| 103 case NE: return EQ; |
| 104 case LT: return GE; |
| 105 case LE: return GT; |
| 106 case GT: return LE; |
| 107 case GE: return LT; |
| 108 case CC: return CS; |
| 109 case LS: return HI; |
| 110 case HI: return LS; |
| 111 case CS: return CC; |
| 112 default: |
| 113 UNREACHABLE(); |
| 114 return EQ; |
| 115 } |
| 116 } |
| 117 |
| 118 |
| 119 // Detect pattern when one value is zero and another is a power of 2. |
| 120 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { |
| 121 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || |
| 122 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); |
| 123 } |
| 124 |
| 125 |
| 100 LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const { | 126 LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const { |
| 101 UNIMPLEMENTED(); | 127 comparison()->InitializeLocationSummary(opt); |
| 102 return NULL; | 128 return comparison()->locs(); |
| 103 } | 129 } |
| 104 | 130 |
| 105 | 131 |
| 106 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 132 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 107 UNIMPLEMENTED(); | 133 const Register result = locs()->out(0).reg(); |
| 134 |
| 135 Location left = locs()->in(0); |
| 136 Location right = locs()->in(1); |
| 137 ASSERT(!left.IsConstant() || !right.IsConstant()); |
| 138 |
| 139 // Emit comparison code. This must not overwrite the result register. |
| 140 BranchLabels labels = { NULL, NULL, NULL }; |
| 141 Condition true_condition = comparison()->EmitComparisonCode(compiler, labels); |
| 142 |
| 143 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_); |
| 144 |
| 145 intptr_t true_value = if_true_; |
| 146 intptr_t false_value = if_false_; |
| 147 |
| 148 if (is_power_of_two_kind) { |
| 149 if (true_value == 0) { |
| 150 // We need to have zero in result on true_condition. |
| 151 true_condition = NegateCondition(true_condition); |
| 152 } |
| 153 } else { |
| 154 if (true_value == 0) { |
| 155 // Swap values so that false_value is zero. |
| 156 intptr_t temp = true_value; |
| 157 true_value = false_value; |
| 158 false_value = temp; |
| 159 } else { |
| 160 true_condition = NegateCondition(true_condition); |
| 161 } |
| 162 } |
| 163 |
| 164 // TODO(zra): replace with cinc(result, ZR, ZR, true_condition) |
| 165 __ LoadImmediate(TMP, 1, kNoPP); |
| 166 __ csel(result, TMP, ZR, true_condition); |
| 167 |
| 168 if (is_power_of_two_kind) { |
| 169 const intptr_t shift = |
| 170 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); |
| 171 __ Lsl(result, result, shift + kSmiTagSize); |
| 172 } else { |
| 173 __ sub(result, result, Operand(1)); |
| 174 const int32_t val = |
| 175 Smi::RawValue(true_value) - Smi::RawValue(false_value); |
| 176 __ AndImmediate(result, result, val, PP); |
| 177 if (false_value != 0) { |
| 178 __ AddImmediate(result, result, Smi::RawValue(false_value), PP); |
| 179 } |
| 180 } |
| 108 } | 181 } |
| 109 | 182 |
| 110 | 183 |
| 111 LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const { | 184 LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const { |
| 112 const intptr_t kNumInputs = 1; | 185 const intptr_t kNumInputs = 1; |
| 113 const intptr_t kNumTemps = 0; | 186 const intptr_t kNumTemps = 0; |
| 114 LocationSummary* summary = | 187 LocationSummary* summary = |
| 115 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 188 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 116 summary->set_in(0, Location::RegisterLocation(R0)); // Function. | 189 summary->set_in(0, Location::RegisterLocation(R0)); // Function. |
| 117 summary->set_out(0, Location::RegisterLocation(R0)); | 190 summary->set_out(0, Location::RegisterLocation(R0)); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 | 340 |
| 268 void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 341 void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 269 Register obj = locs()->in(0).reg(); | 342 Register obj = locs()->in(0).reg(); |
| 270 Register result = locs()->out(0).reg(); | 343 Register result = locs()->out(0).reg(); |
| 271 | 344 |
| 272 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler); | 345 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler); |
| 273 ASSERT(obj == result); | 346 ASSERT(obj == result); |
| 274 } | 347 } |
| 275 | 348 |
| 276 | 349 |
| 350 static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| 351 switch (kind) { |
| 352 case Token::kEQ: return EQ; |
| 353 case Token::kNE: return NE; |
| 354 case Token::kLT: return LT; |
| 355 case Token::kGT: return GT; |
| 356 case Token::kLTE: return LE; |
| 357 case Token::kGTE: return GE; |
| 358 default: |
| 359 UNREACHABLE(); |
| 360 return VS; |
| 361 } |
| 362 } |
| 363 |
| 364 |
| 365 static Condition FlipCondition(Condition condition) { |
| 366 switch (condition) { |
| 367 case EQ: return EQ; |
| 368 case NE: return NE; |
| 369 case LT: return GT; |
| 370 case LE: return GE; |
| 371 case GT: return LT; |
| 372 case GE: return LE; |
| 373 case CC: return HI; |
| 374 case LS: return CS; |
| 375 case HI: return CC; |
| 376 case CS: return LS; |
| 377 default: |
| 378 UNREACHABLE(); |
| 379 return EQ; |
| 380 } |
| 381 } |
| 382 |
| 383 |
| 384 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 385 Condition true_condition, |
| 386 BranchLabels labels) { |
| 387 if (labels.fall_through == labels.false_label) { |
| 388 // If the next block is the false successor we will fall through to it. |
| 389 __ b(labels.true_label, true_condition); |
| 390 } else { |
| 391 // If the next block is not the false successor we will branch to it. |
| 392 Condition false_condition = NegateCondition(true_condition); |
| 393 __ b(labels.false_label, false_condition); |
| 394 |
| 395 // Fall through or jump to the true successor. |
| 396 if (labels.fall_through != labels.true_label) { |
| 397 __ b(labels.true_label); |
| 398 } |
| 399 } |
| 400 } |
| 401 |
| 402 |
| 403 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 404 LocationSummary* locs, |
| 405 Token::Kind kind) { |
| 406 Location left = locs->in(0); |
| 407 Location right = locs->in(1); |
| 408 ASSERT(!left.IsConstant() || !right.IsConstant()); |
| 409 |
| 410 Condition true_condition = TokenKindToSmiCondition(kind); |
| 411 |
| 412 if (left.IsConstant()) { |
| 413 __ CompareObject(right.reg(), left.constant(), PP); |
| 414 true_condition = FlipCondition(true_condition); |
| 415 } else if (right.IsConstant()) { |
| 416 __ CompareObject(left.reg(), right.constant(), PP); |
| 417 } else { |
| 418 __ CompareRegisters(left.reg(), right.reg()); |
| 419 } |
| 420 return true_condition; |
| 421 } |
| 422 |
| 423 |
| 277 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { | 424 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { |
| 278 UNIMPLEMENTED(); | 425 const intptr_t kNumInputs = 2; |
| 426 if (operation_cid() == kDoubleCid) { |
| 427 const intptr_t kNumTemps = 0; |
| 428 LocationSummary* locs = |
| 429 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 430 locs->set_in(0, Location::RequiresFpuRegister()); |
| 431 locs->set_in(1, Location::RequiresFpuRegister()); |
| 432 locs->set_out(0, Location::RequiresRegister()); |
| 433 return locs; |
| 434 } |
| 435 if (operation_cid() == kSmiCid) { |
| 436 const intptr_t kNumTemps = 0; |
| 437 LocationSummary* locs = |
| 438 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 439 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 440 // Only one input can be a constant operand. The case of two constant |
| 441 // operands should be handled by constant propagation. |
| 442 // Only right can be a stack slot. |
| 443 locs->set_in(1, locs->in(0).IsConstant() |
| 444 ? Location::RequiresRegister() |
| 445 : Location::RegisterOrConstant(right())); |
| 446 locs->set_out(0, Location::RequiresRegister()); |
| 447 return locs; |
| 448 } |
| 449 UNREACHABLE(); |
| 279 return NULL; | 450 return NULL; |
| 280 } | 451 } |
| 281 | 452 |
| 282 | 453 |
| 283 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 454 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 284 BranchLabels labels) { | 455 BranchLabels labels) { |
| 285 UNIMPLEMENTED(); | 456 if (operation_cid() == kSmiCid) { |
| 286 return VS; | 457 return EmitSmiComparisonOp(compiler, locs(), kind()); |
| 458 } else { |
| 459 UNIMPLEMENTED(); |
| 460 return VS; |
| 461 } |
| 287 } | 462 } |
| 288 | 463 |
| 289 | 464 |
| 290 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 465 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 291 UNIMPLEMENTED(); | 466 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); |
| 467 |
| 468 Label is_true, is_false; |
| 469 BranchLabels labels = { &is_true, &is_false, &is_false }; |
| 470 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 471 EmitBranchOnCondition(compiler, true_condition, labels); |
| 472 |
| 473 // TODO(zra): instead of branching, use the csel instruction to get |
| 474 // True or False into result. |
| 475 Register result = locs()->out(0).reg(); |
| 476 Label done; |
| 477 __ Bind(&is_false); |
| 478 __ LoadObject(result, Bool::False(), PP); |
| 479 __ b(&done); |
| 480 __ Bind(&is_true); |
| 481 __ LoadObject(result, Bool::True(), PP); |
| 482 __ Bind(&done); |
| 292 } | 483 } |
| 293 | 484 |
| 294 | 485 |
| 295 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 486 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 296 BranchInstr* branch) { | 487 BranchInstr* branch) { |
| 297 UNIMPLEMENTED(); | 488 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 489 |
| 490 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 491 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 492 EmitBranchOnCondition(compiler, true_condition, labels); |
| 298 } | 493 } |
| 299 | 494 |
| 300 | 495 |
| 301 LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const { | 496 LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const { |
| 302 UNIMPLEMENTED(); | 497 const intptr_t kNumInputs = 2; |
| 303 return NULL; | 498 const intptr_t kNumTemps = 0; |
| 499 LocationSummary* locs = |
| 500 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 501 locs->set_in(0, Location::RequiresRegister()); |
| 502 // Only one input can be a constant operand. The case of two constant |
| 503 // operands should be handled by constant propagation. |
| 504 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 505 return locs; |
| 304 } | 506 } |
| 305 | 507 |
| 306 | 508 |
| 307 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 509 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 308 BranchLabels labels) { | 510 BranchLabels labels) { |
| 309 UNIMPLEMENTED(); | 511 Register left = locs()->in(0).reg(); |
| 310 return VS; | 512 Location right = locs()->in(1); |
| 513 if (right.IsConstant()) { |
| 514 ASSERT(right.constant().IsSmi()); |
| 515 const int32_t imm = |
| 516 reinterpret_cast<int64_t>(right.constant().raw()); |
| 517 __ TestImmediate(left, imm, PP); |
| 518 } else { |
| 519 __ tst(left, Operand(right.reg())); |
| 520 } |
| 521 Condition true_condition = (kind() == Token::kNE) ? NE : EQ; |
| 522 return true_condition; |
| 311 } | 523 } |
| 312 | 524 |
| 525 |
| 313 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 526 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 314 UNIMPLEMENTED(); | 527 // Never emitted outside of the BranchInstr. |
| 528 UNREACHABLE(); |
| 315 } | 529 } |
| 316 | 530 |
| 317 | 531 |
| 318 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 532 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 319 BranchInstr* branch) { | 533 BranchInstr* branch) { |
| 320 UNIMPLEMENTED(); | 534 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 535 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 536 EmitBranchOnCondition(compiler, true_condition, labels); |
| 321 } | 537 } |
| 322 | 538 |
| 323 | 539 |
| 324 LocationSummary* TestCidsInstr::MakeLocationSummary(bool opt) const { | 540 LocationSummary* TestCidsInstr::MakeLocationSummary(bool opt) const { |
| 325 const intptr_t kNumInputs = 1; | 541 const intptr_t kNumInputs = 1; |
| 326 const intptr_t kNumTemps = 1; | 542 const intptr_t kNumTemps = 1; |
| 327 LocationSummary* locs = | 543 LocationSummary* locs = |
| 328 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 544 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 329 locs->set_in(0, Location::RequiresRegister()); | 545 locs->set_in(0, Location::RequiresRegister()); |
| 330 locs->set_temp(0, Location::RequiresRegister()); | 546 locs->set_temp(0, Location::RequiresRegister()); |
| 331 locs->set_out(0, Location::RequiresRegister()); | 547 locs->set_out(0, Location::RequiresRegister()); |
| 332 return locs; | 548 return locs; |
| 333 } | 549 } |
| 334 | 550 |
| 335 | 551 |
| 336 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 552 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 337 BranchLabels labels) { | 553 BranchLabels labels) { |
| 338 UNIMPLEMENTED(); | 554 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT)); |
| 555 Register val_reg = locs()->in(0).reg(); |
| 556 Register cid_reg = locs()->temp(0).reg(); |
| 557 |
| 558 Label* deopt = CanDeoptimize() ? |
| 559 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL; |
| 560 |
| 561 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
| 562 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
| 563 ASSERT(data[0] == kSmiCid); |
| 564 bool result = data[1] == true_result; |
| 565 __ tsti(val_reg, kSmiTagMask); |
| 566 __ b(result ? labels.true_label : labels.false_label, EQ); |
| 567 __ LoadClassId(cid_reg, val_reg); |
| 568 |
| 569 for (intptr_t i = 2; i < data.length(); i += 2) { |
| 570 const intptr_t test_cid = data[i]; |
| 571 ASSERT(test_cid != kSmiCid); |
| 572 result = data[i + 1] == true_result; |
| 573 __ CompareImmediate(cid_reg, test_cid, PP); |
| 574 __ b(result ? labels.true_label : labels.false_label, EQ); |
| 575 } |
| 576 // No match found, deoptimize or false. |
| 577 if (deopt == NULL) { |
| 578 Label* target = result ? labels.false_label : labels.true_label; |
| 579 if (target != labels.fall_through) { |
| 580 __ b(target); |
| 581 } |
| 582 } else { |
| 583 __ b(deopt); |
| 584 } |
| 585 // Dummy result as the last instruction is a jump, any conditional |
| 586 // branch using the result will therefore be skipped. |
| 339 return EQ; | 587 return EQ; |
| 340 } | 588 } |
| 341 | 589 |
| 342 | 590 |
| 343 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 591 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 344 BranchInstr* branch) { | 592 BranchInstr* branch) { |
| 345 UNIMPLEMENTED(); | 593 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 594 EmitComparisonCode(compiler, labels); |
| 346 } | 595 } |
| 347 | 596 |
| 348 | 597 |
| 349 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 598 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 350 UNIMPLEMENTED(); | 599 Register result_reg = locs()->out(0).reg(); |
| 600 Label is_true, is_false, done; |
| 601 BranchLabels labels = { &is_true, &is_false, &is_false }; |
| 602 EmitComparisonCode(compiler, labels); |
| 603 // TODO(zra): instead of branching, use the csel instruction to get |
| 604 // True or False into result. |
| 605 __ Bind(&is_false); |
| 606 __ LoadObject(result_reg, Bool::False(), PP); |
| 607 __ b(&done); |
| 608 __ Bind(&is_true); |
| 609 __ LoadObject(result_reg, Bool::True(), PP); |
| 610 __ Bind(&done); |
| 351 } | 611 } |
| 352 | 612 |
| 353 | 613 |
| 354 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { | 614 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { |
| 355 UNIMPLEMENTED(); | 615 const intptr_t kNumInputs = 2; |
| 356 return NULL; | 616 const intptr_t kNumTemps = 0; |
| 617 if (operation_cid() == kDoubleCid) { |
| 618 LocationSummary* summary = |
| 619 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 620 summary->set_in(0, Location::RequiresFpuRegister()); |
| 621 summary->set_in(1, Location::RequiresFpuRegister()); |
| 622 summary->set_out(0, Location::RequiresRegister()); |
| 623 return summary; |
| 624 } |
| 625 ASSERT(operation_cid() == kSmiCid); |
| 626 LocationSummary* summary = |
| 627 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 628 summary->set_in(0, Location::RegisterOrConstant(left())); |
| 629 // Only one input can be a constant operand. The case of two constant |
| 630 // operands should be handled by constant propagation. |
| 631 summary->set_in(1, summary->in(0).IsConstant() |
| 632 ? Location::RequiresRegister() |
| 633 : Location::RegisterOrConstant(right())); |
| 634 summary->set_out(0, Location::RequiresRegister()); |
| 635 return summary; |
| 357 } | 636 } |
| 358 | 637 |
| 359 | 638 |
| 360 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 639 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 361 BranchLabels labels) { | 640 BranchLabels labels) { |
| 362 UNIMPLEMENTED(); | 641 if (operation_cid() == kSmiCid) { |
| 363 return VS; | 642 return EmitSmiComparisonOp(compiler, locs(), kind()); |
| 643 } else { |
| 644 UNIMPLEMENTED(); |
| 645 return VS; |
| 646 } |
| 364 } | 647 } |
| 365 | 648 |
| 366 | 649 |
| 367 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 650 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 368 UNIMPLEMENTED(); | 651 Label is_true, is_false; |
| 652 BranchLabels labels = { &is_true, &is_false, &is_false }; |
| 653 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 654 EmitBranchOnCondition(compiler, true_condition, labels); |
| 655 // TODO(zra): instead of branching, use the csel instruction to get |
| 656 // True or False into result. |
| 657 Register result = locs()->out(0).reg(); |
| 658 Label done; |
| 659 __ Bind(&is_false); |
| 660 __ LoadObject(result, Bool::False(), PP); |
| 661 __ b(&done); |
| 662 __ Bind(&is_true); |
| 663 __ LoadObject(result, Bool::True(), PP); |
| 664 __ Bind(&done); |
| 369 } | 665 } |
| 370 | 666 |
| 371 | 667 |
| 372 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 668 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 373 BranchInstr* branch) { | 669 BranchInstr* branch) { |
| 374 UNIMPLEMENTED(); | 670 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 671 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 672 EmitBranchOnCondition(compiler, true_condition, labels); |
| 375 } | 673 } |
| 376 | 674 |
| 377 | 675 |
| 378 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const { | 676 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const { |
| 379 const intptr_t kNumInputs = 0; | 677 const intptr_t kNumInputs = 0; |
| 380 const intptr_t kNumTemps = 3; | 678 const intptr_t kNumTemps = 3; |
| 381 LocationSummary* locs = | 679 LocationSummary* locs = |
| 382 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 680 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 383 locs->set_temp(0, Location::RegisterLocation(R1)); | 681 locs->set_temp(0, Location::RegisterLocation(R1)); |
| 384 locs->set_temp(1, Location::RegisterLocation(R2)); | 682 locs->set_temp(1, Location::RegisterLocation(R2)); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 __ LoadImmediate(R1, NativeArguments::ComputeArgcTag(function()), PP); | 728 __ LoadImmediate(R1, NativeArguments::ComputeArgcTag(function()), PP); |
| 431 compiler->GenerateCall(token_pos(), | 729 compiler->GenerateCall(token_pos(), |
| 432 stub_entry, | 730 stub_entry, |
| 433 PcDescriptors::kOther, | 731 PcDescriptors::kOther, |
| 434 locs()); | 732 locs()); |
| 435 __ Pop(result); | 733 __ Pop(result); |
| 436 } | 734 } |
| 437 | 735 |
| 438 | 736 |
| 439 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const { | 737 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const { |
| 440 UNIMPLEMENTED(); | 738 const intptr_t kNumInputs = 1; |
| 441 return NULL; | 739 // TODO(fschneider): Allow immediate operands for the char code. |
| 740 return LocationSummary::Make(kNumInputs, |
| 741 Location::RequiresRegister(), |
| 742 LocationSummary::kNoCall); |
| 442 } | 743 } |
| 443 | 744 |
| 444 | 745 |
| 445 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 746 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 446 UNIMPLEMENTED(); | 747 Register char_code = locs()->in(0).reg(); |
| 748 Register result = locs()->out(0).reg(); |
| 749 __ LoadImmediate(result, |
| 750 reinterpret_cast<uword>(Symbols::PredefinedAddress()), PP); |
| 751 __ AddImmediate( |
| 752 result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize, PP); |
| 753 __ Asr(TMP, char_code, kSmiTagShift); // Untag to use scaled adress mode. |
| 754 __ ldr(result, Address(result, TMP, UXTX, Address::Scaled)); |
| 447 } | 755 } |
| 448 | 756 |
| 449 | 757 |
| 450 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(bool opt) const { | 758 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(bool opt) const { |
| 451 UNIMPLEMENTED(); | 759 const intptr_t kNumInputs = 1; |
| 452 return NULL; | 760 return LocationSummary::Make(kNumInputs, |
| 761 Location::RequiresRegister(), |
| 762 LocationSummary::kNoCall); |
| 453 } | 763 } |
| 454 | 764 |
| 455 | 765 |
| 456 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 766 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 457 UNIMPLEMENTED(); | 767 ASSERT(cid_ == kOneByteStringCid); |
| 768 Register str = locs()->in(0).reg(); |
| 769 Register result = locs()->out(0).reg(); |
| 770 __ LoadFieldFromOffset(result, str, String::length_offset()); |
| 771 __ CompareImmediate(result, Smi::RawValue(1), PP); |
| 772 __ LoadImmediate(TMP, Smi::RawValue(-1), PP); |
| 773 __ ldr(TMP2, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte); |
| 774 __ csel(result, TMP, result, NE); |
| 775 __ csel(result, TMP2, result, EQ); |
| 776 __ SmiTag(result); |
| 458 } | 777 } |
| 459 | 778 |
| 460 | 779 |
| 461 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const { | 780 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const { |
| 462 const intptr_t kNumInputs = 1; | 781 const intptr_t kNumInputs = 1; |
| 463 const intptr_t kNumTemps = 0; | 782 const intptr_t kNumTemps = 0; |
| 464 LocationSummary* summary = | 783 LocationSummary* summary = |
| 465 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 784 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 466 summary->set_in(0, Location::RegisterLocation(R0)); | 785 summary->set_in(0, Location::RegisterLocation(R0)); |
| 467 summary->set_out(0, Location::RegisterLocation(R0)); | 786 summary->set_out(0, Location::RegisterLocation(R0)); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP); | 831 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP); |
| 513 __ b(&done); | 832 __ b(&done); |
| 514 __ Bind(&load); | 833 __ Bind(&load); |
| 515 __ LoadClassId(result, object); | 834 __ LoadClassId(result, object); |
| 516 __ SmiTag(result); | 835 __ SmiTag(result); |
| 517 __ Bind(&done); | 836 __ Bind(&done); |
| 518 } | 837 } |
| 519 | 838 |
| 520 | 839 |
| 521 CompileType LoadIndexedInstr::ComputeType() const { | 840 CompileType LoadIndexedInstr::ComputeType() const { |
| 522 UNIMPLEMENTED(); | 841 switch (class_id_) { |
| 523 return CompileType::Dynamic(); | 842 case kArrayCid: |
| 843 case kImmutableArrayCid: |
| 844 return CompileType::Dynamic(); |
| 845 |
| 846 case kTypedDataFloat32ArrayCid: |
| 847 case kTypedDataFloat64ArrayCid: |
| 848 return CompileType::FromCid(kDoubleCid); |
| 849 case kTypedDataFloat32x4ArrayCid: |
| 850 return CompileType::FromCid(kFloat32x4Cid); |
| 851 case kTypedDataInt32x4ArrayCid: |
| 852 return CompileType::FromCid(kInt32x4Cid); |
| 853 case kTypedDataFloat64x2ArrayCid: |
| 854 return CompileType::FromCid(kFloat64x2Cid); |
| 855 |
| 856 case kTypedDataInt8ArrayCid: |
| 857 case kTypedDataUint8ArrayCid: |
| 858 case kTypedDataUint8ClampedArrayCid: |
| 859 case kExternalTypedDataUint8ArrayCid: |
| 860 case kExternalTypedDataUint8ClampedArrayCid: |
| 861 case kTypedDataInt16ArrayCid: |
| 862 case kTypedDataUint16ArrayCid: |
| 863 case kOneByteStringCid: |
| 864 case kTwoByteStringCid: |
| 865 case kTypedDataInt32ArrayCid: |
| 866 case kTypedDataUint32ArrayCid: |
| 867 return CompileType::FromCid(kSmiCid); |
| 868 |
| 869 default: |
| 870 UNIMPLEMENTED(); |
| 871 return CompileType::Dynamic(); |
| 872 } |
| 524 } | 873 } |
| 525 | 874 |
| 526 | 875 |
| 527 Representation LoadIndexedInstr::representation() const { | 876 Representation LoadIndexedInstr::representation() const { |
| 528 UNIMPLEMENTED(); | 877 switch (class_id_) { |
| 529 return kTagged; | 878 case kArrayCid: |
| 879 case kImmutableArrayCid: |
| 880 case kTypedDataInt8ArrayCid: |
| 881 case kTypedDataUint8ArrayCid: |
| 882 case kTypedDataUint8ClampedArrayCid: |
| 883 case kExternalTypedDataUint8ArrayCid: |
| 884 case kExternalTypedDataUint8ClampedArrayCid: |
| 885 case kTypedDataInt16ArrayCid: |
| 886 case kTypedDataUint16ArrayCid: |
| 887 case kOneByteStringCid: |
| 888 case kTwoByteStringCid: |
| 889 case kTypedDataInt32ArrayCid: |
| 890 case kTypedDataUint32ArrayCid: |
| 891 return kTagged; |
| 892 case kTypedDataFloat32ArrayCid: |
| 893 case kTypedDataFloat64ArrayCid: |
| 894 return kUnboxedDouble; |
| 895 case kTypedDataInt32x4ArrayCid: |
| 896 return kUnboxedInt32x4; |
| 897 case kTypedDataFloat32x4ArrayCid: |
| 898 return kUnboxedFloat32x4; |
| 899 case kTypedDataFloat64x2ArrayCid: |
| 900 return kUnboxedFloat64x2; |
| 901 default: |
| 902 UNIMPLEMENTED(); |
| 903 return kTagged; |
| 904 } |
| 530 } | 905 } |
| 531 | 906 |
| 532 | 907 |
| 533 LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const { | 908 LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const { |
| 534 UNIMPLEMENTED(); | 909 const intptr_t kNumInputs = 2; |
| 535 return NULL; | 910 const intptr_t kNumTemps = 0; |
| 911 LocationSummary* locs = |
| 912 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 913 locs->set_in(0, Location::RequiresRegister()); |
| 914 // The smi index is either untagged (element size == 1), or it is left smi |
| 915 // tagged (for all element sizes > 1). |
| 916 // TODO(regis): Revisit and see if the index can be immediate. |
| 917 locs->set_in(1, Location::WritableRegister()); |
| 918 if ((representation() == kUnboxedDouble) || |
| 919 (representation() == kUnboxedFloat32x4) || |
| 920 (representation() == kUnboxedInt32x4) || |
| 921 (representation() == kUnboxedFloat64x2)) { |
| 922 locs->set_out(0, Location::RequiresFpuRegister()); |
| 923 } else { |
| 924 locs->set_out(0, Location::RequiresRegister()); |
| 925 } |
| 926 return locs; |
| 536 } | 927 } |
| 537 | 928 |
| 538 | 929 |
| 539 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 930 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 540 UNIMPLEMENTED(); | 931 Register array = locs()->in(0).reg(); |
| 541 } | 932 Location index = locs()->in(1); |
| 542 | 933 |
| 543 | 934 Address element_address(kNoRegister, 0); |
| 935 ASSERT(index.IsRegister()); // TODO(regis): Revisit. |
| 936 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays |
| 937 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the |
| 938 // index is expected to be untagged before accessing. |
| 939 ASSERT(kSmiTagShift == 1); |
| 940 switch (index_scale()) { |
| 941 case 1: { |
| 942 __ SmiUntag(index.reg()); |
| 943 break; |
| 944 } |
| 945 case 2: { |
| 946 break; |
| 947 } |
| 948 case 4: { |
| 949 __ Lsl(index.reg(), index.reg(), 1); |
| 950 break; |
| 951 } |
| 952 case 8: { |
| 953 __ Lsl(index.reg(), index.reg(), 2); |
| 954 break; |
| 955 } |
| 956 case 16: { |
| 957 __ Lsl(index.reg(), index.reg(), 3); |
| 958 break; |
| 959 } |
| 960 default: |
| 961 UNREACHABLE(); |
| 962 } |
| 963 |
| 964 if (!IsExternal()) { |
| 965 ASSERT(this->array()->definition()->representation() == kTagged); |
| 966 __ AddImmediate(index.reg(), index.reg(), |
| 967 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag, PP); |
| 968 } |
| 969 element_address = Address(array, index.reg(), UXTX, Address::Unscaled); |
| 970 |
| 971 if ((representation() == kUnboxedDouble) || |
| 972 (representation() == kUnboxedMint) || |
| 973 (representation() == kUnboxedFloat32x4) || |
| 974 (representation() == kUnboxedInt32x4) || |
| 975 (representation() == kUnboxedFloat64x2)) { |
| 976 const VRegister result = locs()->out(0).fpu_reg(); |
| 977 switch (class_id()) { |
| 978 case kTypedDataInt32ArrayCid: |
| 979 case kTypedDataUint32ArrayCid: |
| 980 // TODO(zra): Add when we have simd. |
| 981 UNIMPLEMENTED(); |
| 982 break; |
| 983 case kTypedDataFloat32ArrayCid: |
| 984 // Load single precision float. |
| 985 // TODO(zra): Add when we add single precision floats. |
| 986 UNIMPLEMENTED(); |
| 987 break; |
| 988 case kTypedDataFloat64ArrayCid: |
| 989 // Load double precision float. |
| 990 __ fldrd(result, element_address); |
| 991 break; |
| 992 case kTypedDataFloat64x2ArrayCid: |
| 993 case kTypedDataInt32x4ArrayCid: |
| 994 case kTypedDataFloat32x4ArrayCid: |
| 995 // TODO(zra): Add when we have simd. |
| 996 UNIMPLEMENTED(); |
| 997 break; |
| 998 } |
| 999 return; |
| 1000 } |
| 1001 |
| 1002 Register result = locs()->out(0).reg(); |
| 1003 switch (class_id()) { |
| 1004 case kTypedDataInt8ArrayCid: |
| 1005 ASSERT(index_scale() == 1); |
| 1006 __ ldr(result, element_address, kByte); |
| 1007 __ SmiTag(result); |
| 1008 break; |
| 1009 case kTypedDataUint8ArrayCid: |
| 1010 case kTypedDataUint8ClampedArrayCid: |
| 1011 case kExternalTypedDataUint8ArrayCid: |
| 1012 case kExternalTypedDataUint8ClampedArrayCid: |
| 1013 case kOneByteStringCid: |
| 1014 ASSERT(index_scale() == 1); |
| 1015 __ ldr(result, element_address, kUnsignedByte); |
| 1016 __ SmiTag(result); |
| 1017 break; |
| 1018 case kTypedDataInt16ArrayCid: |
| 1019 __ ldr(result, element_address, kHalfword); |
| 1020 __ SmiTag(result); |
| 1021 break; |
| 1022 case kTypedDataUint16ArrayCid: |
| 1023 case kTwoByteStringCid: |
| 1024 __ ldr(result, element_address, kUnsignedHalfword); |
| 1025 __ SmiTag(result); |
| 1026 break; |
| 1027 case kTypedDataInt32ArrayCid: |
| 1028 __ ldr(result, element_address, kWord); |
| 1029 __ SmiTag(result); |
| 1030 break; |
| 1031 case kTypedDataUint32ArrayCid: |
| 1032 __ ldr(result, element_address, kUnsignedWord); |
| 1033 break; |
| 1034 default: |
| 1035 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid)); |
| 1036 __ ldr(result, element_address); |
| 1037 break; |
| 1038 } |
| 1039 } |
| 1040 |
| 1041 |
| 544 Representation StoreIndexedInstr::RequiredInputRepresentation( | 1042 Representation StoreIndexedInstr::RequiredInputRepresentation( |
| 545 intptr_t idx) const { | 1043 intptr_t idx) const { |
| 546 // Array can be a Dart object or a pointer to external data. | 1044 // Array can be a Dart object or a pointer to external data. |
| 547 if (idx == 0) return kNoRepresentation; // Flexible input representation. | 1045 if (idx == 0) return kNoRepresentation; // Flexible input representation. |
| 548 if (idx == 1) return kTagged; // Index is a smi. | 1046 if (idx == 1) return kTagged; // Index is a smi. |
| 549 ASSERT(idx == 2); | 1047 ASSERT(idx == 2); |
| 550 switch (class_id_) { | 1048 switch (class_id_) { |
| 551 case kArrayCid: | 1049 case kArrayCid: |
| 552 case kOneByteStringCid: | 1050 case kOneByteStringCid: |
| 553 case kTypedDataInt8ArrayCid: | 1051 case kTypedDataInt8ArrayCid: |
| (...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1381 __ StoreIntoObject(temp, | 1879 __ StoreIntoObject(temp, |
| 1382 FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi()); | 1880 FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi()); |
| 1383 } else { | 1881 } else { |
| 1384 __ StoreIntoObjectNoBarrier( | 1882 __ StoreIntoObjectNoBarrier( |
| 1385 temp, FieldAddress(temp, Field::value_offset()), value); | 1883 temp, FieldAddress(temp, Field::value_offset()), value); |
| 1386 } | 1884 } |
| 1387 } | 1885 } |
| 1388 | 1886 |
| 1389 | 1887 |
| 1390 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const { | 1888 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const { |
| 1391 UNIMPLEMENTED(); | 1889 const intptr_t kNumInputs = 3; |
| 1392 return NULL; | 1890 const intptr_t kNumTemps = 0; |
| 1891 LocationSummary* summary = |
| 1892 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1893 summary->set_in(0, Location::RegisterLocation(R0)); |
| 1894 summary->set_in(1, Location::RegisterLocation(R2)); |
| 1895 summary->set_in(2, Location::RegisterLocation(R1)); |
| 1896 summary->set_out(0, Location::RegisterLocation(R0)); |
| 1897 return summary; |
| 1393 } | 1898 } |
| 1394 | 1899 |
| 1395 | 1900 |
| 1396 void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1901 void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1397 UNIMPLEMENTED(); | 1902 ASSERT(locs()->in(0).reg() == R0); // Value. |
| 1903 ASSERT(locs()->in(1).reg() == R2); // Instantiator. |
| 1904 ASSERT(locs()->in(2).reg() == R1); // Instantiator type arguments. |
| 1905 |
| 1906 compiler->GenerateInstanceOf(token_pos(), |
| 1907 deopt_id(), |
| 1908 type(), |
| 1909 negate_result(), |
| 1910 locs()); |
| 1911 ASSERT(locs()->out(0).reg() == R0); |
| 1398 } | 1912 } |
| 1399 | 1913 |
| 1400 | 1914 |
| 1401 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const { | 1915 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const { |
| 1402 const intptr_t kNumInputs = 2; | 1916 const intptr_t kNumInputs = 2; |
| 1403 const intptr_t kNumTemps = 0; | 1917 const intptr_t kNumTemps = 0; |
| 1404 LocationSummary* locs = | 1918 LocationSummary* locs = |
| 1405 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 1919 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1406 locs->set_in(kElementTypePos, Location::RegisterLocation(R1)); | 1920 locs->set_in(kElementTypePos, Location::RegisterLocation(R1)); |
| 1407 locs->set_in(kLengthPos, Location::RegisterLocation(R2)); | 1921 locs->set_in(kLengthPos, Location::RegisterLocation(R2)); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 } | 2083 } |
| 1570 | 2084 |
| 1571 __ Bind(&load_pointer); | 2085 __ Bind(&load_pointer); |
| 1572 } | 2086 } |
| 1573 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes()); | 2087 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes()); |
| 1574 __ Bind(&done); | 2088 __ Bind(&done); |
| 1575 } | 2089 } |
| 1576 | 2090 |
| 1577 | 2091 |
| 1578 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const { | 2092 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const { |
| 1579 UNIMPLEMENTED(); | 2093 const intptr_t kNumInputs = 1; |
| 1580 return NULL; | 2094 const intptr_t kNumTemps = 0; |
| 2095 LocationSummary* locs = |
| 2096 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 2097 locs->set_in(0, Location::RegisterLocation(R0)); |
| 2098 locs->set_out(0, Location::RegisterLocation(R0)); |
| 2099 return locs; |
| 1581 } | 2100 } |
| 1582 | 2101 |
| 1583 | 2102 |
| 1584 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2103 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1585 UNIMPLEMENTED(); | 2104 Register instantiator_reg = locs()->in(0).reg(); |
| 2105 Register result_reg = locs()->out(0).reg(); |
| 2106 |
| 2107 // 'instantiator_reg' is the instantiator TypeArguments object (or null). |
| 2108 // A runtime call to instantiate the type is required. |
| 2109 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. |
| 2110 __ PushObject(type(), PP); |
| 2111 __ Push(instantiator_reg); // Push instantiator type arguments. |
| 2112 compiler->GenerateRuntimeCall(token_pos(), |
| 2113 deopt_id(), |
| 2114 kInstantiateTypeRuntimeEntry, |
| 2115 2, |
| 2116 locs()); |
| 2117 __ Drop(2); // Drop instantiator and uninstantiated type. |
| 2118 __ Pop(result_reg); // Pop instantiated type. |
| 2119 ASSERT(instantiator_reg == result_reg); |
| 1586 } | 2120 } |
| 1587 | 2121 |
| 1588 | 2122 |
| 1589 LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary( | 2123 LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary( |
| 1590 bool opt) const { | 2124 bool opt) const { |
| 1591 const intptr_t kNumInputs = 1; | 2125 const intptr_t kNumInputs = 1; |
| 1592 const intptr_t kNumTemps = 0; | 2126 const intptr_t kNumTemps = 0; |
| 1593 LocationSummary* locs = | 2127 LocationSummary* locs = |
| 1594 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 2128 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1595 locs->set_in(0, Location::RegisterLocation(R0)); | 2129 locs->set_in(0, Location::RegisterLocation(R0)); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1826 __ CompareImmediate(temp, threshold, PP); | 2360 __ CompareImmediate(temp, threshold, PP); |
| 1827 __ b(slow_path->osr_entry_label(), GE); | 2361 __ b(slow_path->osr_entry_label(), GE); |
| 1828 } | 2362 } |
| 1829 if (compiler->ForceSlowPathForStackOverflow()) { | 2363 if (compiler->ForceSlowPathForStackOverflow()) { |
| 1830 __ b(slow_path->entry_label()); | 2364 __ b(slow_path->entry_label()); |
| 1831 } | 2365 } |
| 1832 __ Bind(slow_path->exit_label()); | 2366 __ Bind(slow_path->exit_label()); |
| 1833 } | 2367 } |
| 1834 | 2368 |
| 1835 | 2369 |
| 2370 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2371 BinarySmiOpInstr* shift_left) { |
| 2372 const bool is_truncating = shift_left->is_truncating(); |
| 2373 const LocationSummary& locs = *shift_left->locs(); |
| 2374 Register left = locs.in(0).reg(); |
| 2375 Register result = locs.out(0).reg(); |
| 2376 Label* deopt = shift_left->CanDeoptimize() ? |
| 2377 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2378 : NULL; |
| 2379 if (locs.in(1).IsConstant()) { |
| 2380 const Object& constant = locs.in(1).constant(); |
| 2381 ASSERT(constant.IsSmi()); |
| 2382 // Immediate shift operation takes 6 bits for the count. |
| 2383 const intptr_t kCountLimit = 0x3F; |
| 2384 const intptr_t value = Smi::Cast(constant).Value(); |
| 2385 if (value == 0) { |
| 2386 __ mov(result, left); |
| 2387 } else if ((value < 0) || (value >= kCountLimit)) { |
| 2388 // This condition may not be known earlier in some cases because |
| 2389 // of constant propagation, inlining, etc. |
| 2390 if ((value >= kCountLimit) && is_truncating) { |
| 2391 __ mov(result, ZR); |
| 2392 } else { |
| 2393 // Result is Mint or exception. |
| 2394 __ b(deopt); |
| 2395 } |
| 2396 } else { |
| 2397 if (!is_truncating) { |
| 2398 // Check for overflow (preserve left). |
| 2399 __ Lsl(TMP, left, value); |
| 2400 __ cmp(left, Operand(TMP, ASR, value)); |
| 2401 __ b(deopt, NE); // Overflow. |
| 2402 } |
| 2403 // Shift for result now we know there is no overflow. |
| 2404 __ Lsl(result, left, value); |
| 2405 } |
| 2406 return; |
| 2407 } |
| 2408 |
| 2409 // Right (locs.in(1)) is not constant. |
| 2410 Register right = locs.in(1).reg(); |
| 2411 Range* right_range = shift_left->right()->definition()->range(); |
| 2412 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 2413 // TODO(srdjan): Implement code below for is_truncating(). |
| 2414 // If left is constant, we know the maximal allowed size for right. |
| 2415 const Object& obj = shift_left->left()->BoundConstant(); |
| 2416 if (obj.IsSmi()) { |
| 2417 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2418 if (left_int == 0) { |
| 2419 __ CompareRegisters(right, ZR); |
| 2420 __ b(deopt, MI); |
| 2421 __ mov(result, ZR); |
| 2422 return; |
| 2423 } |
| 2424 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2425 const bool right_needs_check = |
| 2426 (right_range == NULL) || |
| 2427 !right_range->IsWithin(0, max_right - 1); |
| 2428 if (right_needs_check) { |
| 2429 __ CompareImmediate(right, |
| 2430 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); |
| 2431 __ b(deopt, CS); |
| 2432 } |
| 2433 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
| 2434 __ lslv(result, left, TMP); |
| 2435 } |
| 2436 return; |
| 2437 } |
| 2438 |
| 2439 const bool right_needs_check = |
| 2440 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2441 if (is_truncating) { |
| 2442 if (right_needs_check) { |
| 2443 const bool right_may_be_negative = |
| 2444 (right_range == NULL) || |
| 2445 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 2446 if (right_may_be_negative) { |
| 2447 ASSERT(shift_left->CanDeoptimize()); |
| 2448 __ CompareRegisters(right, ZR); |
| 2449 __ b(deopt, MI); |
| 2450 } |
| 2451 |
| 2452 __ CompareImmediate( |
| 2453 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP); |
| 2454 __ csel(result, ZR, result, CS); |
| 2455 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
| 2456 __ lslv(TMP, left, TMP); |
| 2457 __ csel(result, TMP, result, CC); |
| 2458 } else { |
| 2459 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
| 2460 __ lslv(result, left, TMP); |
| 2461 } |
| 2462 } else { |
| 2463 if (right_needs_check) { |
| 2464 ASSERT(shift_left->CanDeoptimize()); |
| 2465 __ CompareImmediate( |
| 2466 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP); |
| 2467 __ b(deopt, CS); |
| 2468 } |
| 2469 // Left is not a constant. |
| 2470 // Check if count too large for handling it inlined. |
| 2471 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2472 // Overflow test (preserve left, right, and IP); |
| 2473 Register temp = locs.temp(0).reg(); |
| 2474 __ lslv(temp, left, TMP); |
| 2475 __ asrv(TMP2, temp, TMP); |
| 2476 __ CompareRegisters(left, TMP2); |
| 2477 __ b(deopt, NE); // Overflow. |
| 2478 // Shift for result now we know there is no overflow. |
| 2479 __ lslv(result, left, TMP); |
| 2480 } |
| 2481 } |
| 2482 |
| 2483 |
| 1836 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { | 2484 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { |
| 1837 UNIMPLEMENTED(); | 2485 const intptr_t kNumInputs = 2; |
| 1838 return NULL; | 2486 const intptr_t kNumTemps = 0; |
| 2487 LocationSummary* summary = |
| 2488 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2489 if (op_kind() == Token::kTRUNCDIV) { |
| 2490 summary->set_in(0, Location::RequiresRegister()); |
| 2491 if (RightIsPowerOfTwoConstant()) { |
| 2492 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2493 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2494 } else { |
| 2495 summary->set_in(1, Location::RequiresRegister()); |
| 2496 } |
| 2497 summary->set_out(0, Location::RequiresRegister()); |
| 2498 return summary; |
| 2499 } |
| 2500 if (op_kind() == Token::kMOD) { |
| 2501 summary->set_in(0, Location::RequiresRegister()); |
| 2502 summary->set_in(1, Location::RequiresRegister()); |
| 2503 summary->set_out(0, Location::RequiresRegister()); |
| 2504 return summary; |
| 2505 } |
| 2506 summary->set_in(0, Location::RequiresRegister()); |
| 2507 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2508 if (((op_kind() == Token::kSHL) && !is_truncating()) || |
| 2509 (op_kind() == Token::kSHR)) { |
| 2510 summary->AddTemp(Location::RequiresRegister()); |
| 2511 } |
| 2512 // We make use of 3-operand instructions by not requiring result register |
| 2513 // to be identical to first input register as on Intel. |
| 2514 summary->set_out(0, Location::RequiresRegister()); |
| 2515 return summary; |
| 1839 } | 2516 } |
| 1840 | 2517 |
| 1841 | 2518 |
| 1842 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2519 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1843 UNIMPLEMENTED(); | 2520 if (op_kind() == Token::kSHL) { |
| 2521 EmitSmiShiftLeft(compiler, this); |
| 2522 return; |
| 2523 } |
| 2524 |
| 2525 ASSERT(!is_truncating()); |
| 2526 const Register left = locs()->in(0).reg(); |
| 2527 const Register result = locs()->out(0).reg(); |
| 2528 Label* deopt = NULL; |
| 2529 if (CanDeoptimize()) { |
| 2530 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| 2531 } |
| 2532 |
| 2533 if (locs()->in(1).IsConstant()) { |
| 2534 const Object& constant = locs()->in(1).constant(); |
| 2535 ASSERT(constant.IsSmi()); |
| 2536 int64_t imm = reinterpret_cast<int64_t>(constant.raw()); |
| 2537 switch (op_kind()) { |
| 2538 case Token::kSUB: { |
| 2539 imm = -imm; // TODO(regis): What if deopt != NULL && imm == 0x80000000? |
| 2540 // Fall through. |
| 2541 } |
| 2542 case Token::kADD: { |
| 2543 if (deopt == NULL) { |
| 2544 __ AddImmediate(result, left, imm, PP); |
| 2545 } else { |
| 2546 __ AddImmediateSetFlags(result, left, imm, PP); |
| 2547 __ b(deopt, VS); } |
| 2548 break; |
| 2549 } |
| 2550 case Token::kMUL: { |
| 2551 // Keep left value tagged and untag right value. |
| 2552 const intptr_t value = Smi::Cast(constant).Value(); |
| 2553 if (deopt == NULL) { |
| 2554 if (value == 2) { |
| 2555 __ Lsl(result, left, 1); |
| 2556 } else { |
| 2557 __ LoadImmediate(TMP, value, PP); |
| 2558 __ mul(result, left, TMP); |
| 2559 } |
| 2560 } else { |
| 2561 if (value == 2) { |
| 2562 __ Asr(TMP, left, 63); // TMP = sign of left. |
| 2563 __ Lsl(result, left, 1); |
| 2564 // TMP: result bits 32..63. |
| 2565 __ cmp(TMP, Operand(result, ASR, 63)); |
| 2566 __ b(deopt, NE); |
| 2567 } else { |
| 2568 __ LoadImmediate(TMP, value, PP); |
| 2569 __ mul(result, left, TMP); |
| 2570 __ smulh(TMP, left, TMP); |
| 2571 // TMP: result bits 64..127. |
| 2572 __ cmp(TMP, Operand(result, ASR, 63)); |
| 2573 __ b(deopt, NE); |
| 2574 } |
| 2575 } |
| 2576 break; |
| 2577 } |
| 2578 case Token::kTRUNCDIV: { |
| 2579 const intptr_t value = Smi::Cast(constant).Value(); |
| 2580 if (value == 1) { |
| 2581 __ mov(result, left); |
| 2582 break; |
| 2583 } else if (value == -1) { |
| 2584 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 2585 // case we cannot negate the result. |
| 2586 __ CompareImmediate(left, 0x8000000000000000LL, kNoPP); |
| 2587 __ b(deopt, EQ); |
| 2588 __ sub(result, ZR, Operand(left)); |
| 2589 break; |
| 2590 } |
| 2591 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2592 const intptr_t shift_count = |
| 2593 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2594 ASSERT(kSmiTagSize == 1); |
| 2595 __ Asr(TMP, left, 63); |
| 2596 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2597 const Register temp = TMP2; |
| 2598 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count)); |
| 2599 ASSERT(shift_count > 0); |
| 2600 __ Asr(result, temp, shift_count); |
| 2601 if (value < 0) { |
| 2602 __ sub(result, ZR, Operand(result)); |
| 2603 } |
| 2604 __ SmiTag(result); |
| 2605 break; |
| 2606 } |
| 2607 case Token::kBIT_AND: |
| 2608 // No overflow check. |
| 2609 __ AndImmediate(result, left, imm, PP); |
| 2610 break; |
| 2611 case Token::kBIT_OR: |
| 2612 // No overflow check. |
| 2613 __ OrImmediate(result, left, imm, PP); |
| 2614 break; |
| 2615 case Token::kBIT_XOR: |
| 2616 // No overflow check. |
| 2617 __ XorImmediate(result, left, imm, PP); |
| 2618 break; |
| 2619 case Token::kSHR: { |
| 2620 // Asr operation masks the count to 6 bits. |
| 2621 const intptr_t kCountLimit = 0x3F; |
| 2622 intptr_t value = Smi::Cast(constant).Value(); |
| 2623 |
| 2624 if (value == 0) { |
| 2625 // TODO(vegorov): should be handled outside. |
| 2626 __ mov(result, left); |
| 2627 break; |
| 2628 } else if (value < 0) { |
| 2629 // TODO(vegorov): should be handled outside. |
| 2630 __ b(deopt); |
| 2631 break; |
| 2632 } |
| 2633 |
| 2634 value = value + kSmiTagSize; |
| 2635 if (value >= kCountLimit) { |
| 2636 value = kCountLimit; |
| 2637 } |
| 2638 |
| 2639 __ Asr(result, left, value); |
| 2640 __ SmiTag(result); |
| 2641 break; |
| 2642 } |
| 2643 default: |
| 2644 UNREACHABLE(); |
| 2645 break; |
| 2646 } |
| 2647 return; |
| 2648 } |
| 2649 |
| 2650 Register right = locs()->in(1).reg(); |
| 2651 Range* right_range = this->right()->definition()->range(); |
| 2652 switch (op_kind()) { |
| 2653 case Token::kADD: { |
| 2654 if (deopt == NULL) { |
| 2655 __ add(result, left, Operand(right)); |
| 2656 } else { |
| 2657 __ adds(result, left, Operand(right)); |
| 2658 __ b(deopt, VS); |
| 2659 } |
| 2660 break; |
| 2661 } |
| 2662 case Token::kSUB: { |
| 2663 if (deopt == NULL) { |
| 2664 __ sub(result, left, Operand(right)); |
| 2665 } else { |
| 2666 __ subs(result, left, Operand(right)); |
| 2667 __ b(deopt, VS); |
| 2668 } |
| 2669 break; |
| 2670 } |
| 2671 case Token::kMUL: { |
| 2672 __ Asr(TMP, left, kSmiTagSize); // SmiUntag left into TMP. |
| 2673 if (deopt == NULL) { |
| 2674 __ mul(result, TMP, right); |
| 2675 } else { |
| 2676 __ mul(result, TMP, right); |
| 2677 __ smulh(TMP, TMP, right); |
| 2678 // TMP: result bits 64..127. |
| 2679 __ cmp(TMP, Operand(result, ASR, 63)); |
| 2680 __ b(deopt, NE); |
| 2681 } |
| 2682 break; |
| 2683 } |
| 2684 case Token::kBIT_AND: { |
| 2685 // No overflow check. |
| 2686 __ and_(result, left, Operand(right)); |
| 2687 break; |
| 2688 } |
| 2689 case Token::kBIT_OR: { |
| 2690 // No overflow check. |
| 2691 __ orr(result, left, Operand(right)); |
| 2692 break; |
| 2693 } |
| 2694 case Token::kBIT_XOR: { |
| 2695 // No overflow check. |
| 2696 __ eor(result, left, Operand(right)); |
| 2697 break; |
| 2698 } |
| 2699 case Token::kTRUNCDIV: { |
| 2700 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 2701 // Handle divide by zero in runtime. |
| 2702 __ CompareRegisters(right, ZR); |
| 2703 __ b(deopt, EQ); |
| 2704 } |
| 2705 const Register temp = TMP2; |
| 2706 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp. |
| 2707 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2708 |
| 2709 __ sdiv(result, temp, TMP); |
| 2710 |
| 2711 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 2712 // case we cannot tag the result. |
| 2713 __ CompareImmediate(result, 0x4000000000000000LL, kNoPP); |
| 2714 __ b(deopt, EQ); |
| 2715 __ SmiTag(result); |
| 2716 break; |
| 2717 } |
| 2718 case Token::kMOD: { |
| 2719 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 2720 // Handle divide by zero in runtime. |
| 2721 __ CompareRegisters(right, ZR); |
| 2722 __ b(deopt, EQ); |
| 2723 } |
| 2724 const Register temp = TMP2; |
| 2725 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp. |
| 2726 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2727 |
| 2728 __ sdiv(result, temp, TMP); |
| 2729 |
| 2730 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2731 __ msub(result, TMP, result, temp); // result <- left - right * result |
| 2732 __ SmiTag(result); |
| 2733 // res = left % right; |
| 2734 // if (res < 0) { |
| 2735 // if (right < 0) { |
| 2736 // res = res - right; |
| 2737 // } else { |
| 2738 // res = res + right; |
| 2739 // } |
| 2740 // } |
| 2741 Label done; |
| 2742 __ CompareRegisters(result, ZR); |
| 2743 __ b(&done, GE); |
| 2744 // Result is negative, adjust it. |
| 2745 __ CompareRegisters(right, ZR); |
| 2746 __ sub(TMP, result, Operand(right)); |
| 2747 __ add(result, result, Operand(right)); |
| 2748 __ csel(result, TMP, result, LT); |
| 2749 __ Bind(&done); |
| 2750 break; |
| 2751 } |
| 2752 case Token::kSHR: { |
| 2753 if (CanDeoptimize()) { |
| 2754 __ CompareRegisters(right, ZR); |
| 2755 __ b(deopt, LT); |
| 2756 } |
| 2757 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
| 2758 // sarl operation masks the count to 6 bits. |
| 2759 const intptr_t kCountLimit = 0x3F; |
| 2760 if ((right_range == NULL) || |
| 2761 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2762 __ LoadImmediate(TMP2, kCountLimit, PP); |
| 2763 __ CompareRegisters(TMP, TMP2); |
| 2764 __ csel(TMP, TMP2, TMP, GT); |
| 2765 } |
| 2766 Register temp = locs()->temp(0).reg(); |
| 2767 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp. |
| 2768 __ Asr(result, temp, TMP); |
| 2769 __ SmiTag(result); |
| 2770 break; |
| 2771 } |
| 2772 case Token::kDIV: { |
| 2773 // Dispatches to 'Double./'. |
| 2774 // TODO(srdjan): Implement as conversion to double and double division. |
| 2775 UNREACHABLE(); |
| 2776 break; |
| 2777 } |
| 2778 case Token::kOR: |
| 2779 case Token::kAND: { |
| 2780 // Flow graph builder has dissected this operation to guarantee correct |
| 2781 // behavior (short-circuit evaluation). |
| 2782 UNREACHABLE(); |
| 2783 break; |
| 2784 } |
| 2785 default: |
| 2786 UNREACHABLE(); |
| 2787 break; |
| 2788 } |
| 1844 } | 2789 } |
| 1845 | 2790 |
| 1846 | 2791 |
| 1847 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { | 2792 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { |
| 1848 UNIMPLEMENTED(); | 2793 UNIMPLEMENTED(); |
| 1849 return NULL; | 2794 return NULL; |
| 1850 } | 2795 } |
| 1851 | 2796 |
| 1852 | 2797 |
| 1853 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2798 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1854 UNIMPLEMENTED(); | 2799 UNIMPLEMENTED(); |
| 1855 } | 2800 } |
| 1856 | 2801 |
| 1857 | 2802 |
| 1858 LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const { | 2803 LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const { |
| 1859 UNIMPLEMENTED(); | 2804 const intptr_t kNumInputs = 1; |
| 1860 return NULL; | 2805 const intptr_t kNumTemps = 1; |
| 2806 LocationSummary* summary = |
| 2807 new LocationSummary(kNumInputs, |
| 2808 kNumTemps, |
| 2809 LocationSummary::kCallOnSlowPath); |
| 2810 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2811 summary->set_temp(0, Location::RequiresRegister()); |
| 2812 summary->set_out(0, Location::RequiresRegister()); |
| 2813 return summary; |
| 1861 } | 2814 } |
| 1862 | 2815 |
| 1863 | 2816 |
| 1864 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2817 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1865 UNIMPLEMENTED(); | 2818 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); |
| 2819 compiler->AddSlowPathCode(slow_path); |
| 2820 |
| 2821 const Register out_reg = locs()->out(0).reg(); |
| 2822 const VRegister value = locs()->in(0).fpu_reg(); |
| 2823 |
| 2824 __ TryAllocate(compiler->double_class(), |
| 2825 slow_path->entry_label(), |
| 2826 out_reg, |
| 2827 locs()->temp(0).reg(), |
| 2828 PP); |
| 2829 __ Bind(slow_path->exit_label()); |
| 2830 __ StoreDFieldToOffset(value, out_reg, Double::value_offset()); |
| 1866 } | 2831 } |
| 1867 | 2832 |
| 1868 | 2833 |
| 1869 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const { | 2834 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const { |
| 1870 UNIMPLEMENTED(); | 2835 UNIMPLEMENTED(); |
| 1871 return NULL; | 2836 return NULL; |
| 1872 } | 2837 } |
| 1873 | 2838 |
| 1874 | 2839 |
| 1875 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2840 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2305 return NULL; | 3270 return NULL; |
| 2306 } | 3271 } |
| 2307 | 3272 |
| 2308 | 3273 |
| 2309 void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3274 void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2310 UNIMPLEMENTED(); | 3275 UNIMPLEMENTED(); |
| 2311 } | 3276 } |
| 2312 | 3277 |
| 2313 | 3278 |
| 2314 LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const { | 3279 LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const { |
| 2315 UNIMPLEMENTED(); | 3280 const intptr_t kNumInputs = 1; |
| 2316 return NULL; | 3281 const intptr_t kNumTemps = 0; |
| 3282 LocationSummary* summary = |
| 3283 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3284 summary->set_in(0, Location::RequiresRegister()); |
| 3285 // We make use of 3-operand instructions by not requiring result register |
| 3286 // to be identical to first input register as on Intel. |
| 3287 summary->set_out(0, Location::RequiresRegister()); |
| 3288 return summary; |
| 2317 } | 3289 } |
| 2318 | 3290 |
| 2319 | 3291 |
| 2320 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3292 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2321 UNIMPLEMENTED(); | 3293 Register value = locs()->in(0).reg(); |
| 3294 Register result = locs()->out(0).reg(); |
| 3295 switch (op_kind()) { |
| 3296 case Token::kNEGATE: { |
| 3297 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); |
| 3298 __ subs(result, ZR, Operand(value)); |
| 3299 __ b(deopt, VS); |
| 3300 break; |
| 3301 } |
| 3302 case Token::kBIT_NOT: |
| 3303 __ mvn(result, value); |
| 3304 // Remove inverted smi-tag. |
| 3305 __ andi(result, result, ~kSmiTagMask); |
| 3306 break; |
| 3307 default: |
| 3308 UNREACHABLE(); |
| 3309 } |
| 2322 } | 3310 } |
| 2323 | 3311 |
| 2324 | 3312 |
| 2325 LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const { | 3313 LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const { |
| 2326 UNIMPLEMENTED(); | 3314 UNIMPLEMENTED(); |
| 2327 return NULL; | 3315 return NULL; |
| 2328 } | 3316 } |
| 2329 | 3317 |
| 2330 | 3318 |
| 2331 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3319 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2404 return NULL; | 3392 return NULL; |
| 2405 } | 3393 } |
| 2406 | 3394 |
| 2407 | 3395 |
| 2408 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3396 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2409 UNIMPLEMENTED(); | 3397 UNIMPLEMENTED(); |
| 2410 } | 3398 } |
| 2411 | 3399 |
| 2412 | 3400 |
| 2413 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { | 3401 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { |
| 2414 UNIMPLEMENTED(); | 3402 // Only use this instruction in optimized code. |
| 2415 return NULL; | 3403 ASSERT(opt); |
| 3404 const intptr_t kNumInputs = 1; |
| 3405 LocationSummary* summary = |
| 3406 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); |
| 3407 if (representation() == kUnboxedDouble) { |
| 3408 if (index() == 0) { |
| 3409 summary->set_in(0, Location::Pair(Location::RequiresFpuRegister(), |
| 3410 Location::Any())); |
| 3411 } else { |
| 3412 ASSERT(index() == 1); |
| 3413 summary->set_in(0, Location::Pair(Location::Any(), |
| 3414 Location::RequiresFpuRegister())); |
| 3415 } |
| 3416 summary->set_out(0, Location::RequiresFpuRegister()); |
| 3417 } else { |
| 3418 ASSERT(representation() == kTagged); |
| 3419 if (index() == 0) { |
| 3420 summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
| 3421 Location::Any())); |
| 3422 } else { |
| 3423 ASSERT(index() == 1); |
| 3424 summary->set_in(0, Location::Pair(Location::Any(), |
| 3425 Location::RequiresRegister())); |
| 3426 } |
| 3427 summary->set_out(0, Location::RequiresRegister()); |
| 3428 } |
| 3429 return summary; |
| 2416 } | 3430 } |
| 2417 | 3431 |
| 2418 | 3432 |
| 2419 void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3433 void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2420 UNIMPLEMENTED(); | 3434 ASSERT(locs()->in(0).IsPairLocation()); |
| 3435 PairLocation* pair = locs()->in(0).AsPairLocation(); |
| 3436 Location in_loc = pair->At(index()); |
| 3437 if (representation() == kUnboxedDouble) { |
| 3438 VRegister out = locs()->out(0).fpu_reg(); |
| 3439 VRegister in = in_loc.fpu_reg(); |
| 3440 __ fmovdd(out, in); |
| 3441 } else { |
| 3442 ASSERT(representation() == kTagged); |
| 3443 Register out = locs()->out(0).reg(); |
| 3444 Register in = in_loc.reg(); |
| 3445 __ mov(out, in); |
| 3446 } |
| 2421 } | 3447 } |
| 2422 | 3448 |
| 2423 | 3449 |
| 2424 LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { | 3450 LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { |
| 2425 UNIMPLEMENTED(); | 3451 UNIMPLEMENTED(); |
| 2426 return NULL; | 3452 return NULL; |
| 2427 } | 3453 } |
| 2428 | 3454 |
| 2429 | 3455 |
| 2430 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3456 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2431 UNIMPLEMENTED(); | 3457 UNIMPLEMENTED(); |
| 2432 } | 3458 } |
| 2433 | 3459 |
| 2434 | 3460 |
| 2435 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( | 3461 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( |
| 2436 bool opt) const { | 3462 bool opt) const { |
| 2437 UNIMPLEMENTED(); | 3463 return MakeCallSummary(); |
| 2438 return NULL; | |
| 2439 } | 3464 } |
| 2440 | 3465 |
| 2441 | 3466 |
| 2442 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3467 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2443 UNIMPLEMENTED(); | 3468 Label* deopt = compiler->AddDeoptStub( |
| 3469 deopt_id(), ICData::kDeoptPolymorphicInstanceCallTestFail); |
| 3470 if (ic_data().NumberOfChecks() == 0) { |
| 3471 __ b(deopt); |
| 3472 return; |
| 3473 } |
| 3474 ASSERT(ic_data().NumArgsTested() == 1); |
| 3475 if (!with_checks()) { |
| 3476 ASSERT(ic_data().HasOneTarget()); |
| 3477 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| 3478 compiler->GenerateStaticCall(deopt_id(), |
| 3479 instance_call()->token_pos(), |
| 3480 target, |
| 3481 instance_call()->ArgumentCount(), |
| 3482 instance_call()->argument_names(), |
| 3483 locs()); |
| 3484 return; |
| 3485 } |
| 3486 |
| 3487 // Load receiver into R0. |
| 3488 __ LoadFromOffset( |
| 3489 R0, SP, (instance_call()->ArgumentCount() - 1) * kWordSize); |
| 3490 |
| 3491 LoadValueCid(compiler, R2, R0, |
| 3492 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); |
| 3493 |
| 3494 compiler->EmitTestAndCall(ic_data(), |
| 3495 R2, // Class id register. |
| 3496 instance_call()->ArgumentCount(), |
| 3497 instance_call()->argument_names(), |
| 3498 deopt, |
| 3499 deopt_id(), |
| 3500 instance_call()->token_pos(), |
| 3501 locs()); |
| 2444 } | 3502 } |
| 2445 | 3503 |
| 2446 | 3504 |
| 2447 LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const { | 3505 LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const { |
| 2448 comparison()->InitializeLocationSummary(opt); | 3506 comparison()->InitializeLocationSummary(opt); |
| 2449 // Branches don't produce a result. | 3507 // Branches don't produce a result. |
| 2450 comparison()->locs()->set_out(0, Location::NoLocation()); | 3508 comparison()->locs()->set_out(0, Location::NoLocation()); |
| 2451 return comparison()->locs(); | 3509 return comparison()->locs(); |
| 2452 } | 3510 } |
| 2453 | 3511 |
| 2454 | 3512 |
| 2455 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3513 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2456 comparison()->EmitBranchCode(compiler, this); | 3514 comparison()->EmitBranchCode(compiler, this); |
| 2457 } | 3515 } |
| 2458 | 3516 |
| 2459 | 3517 |
| 2460 LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const { | 3518 LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const { |
| 2461 UNIMPLEMENTED(); | 3519 const intptr_t kNumInputs = 1; |
| 2462 return NULL; | 3520 const intptr_t kNumTemps = 0; |
| 3521 LocationSummary* summary = |
| 3522 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3523 summary->set_in(0, Location::RequiresRegister()); |
| 3524 if (!IsNullCheck()) { |
| 3525 summary->AddTemp(Location::RequiresRegister()); |
| 3526 } |
| 3527 return summary; |
| 2463 } | 3528 } |
| 2464 | 3529 |
| 2465 | 3530 |
| 2466 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3531 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2467 UNIMPLEMENTED(); | 3532 const ICData::DeoptReasonId deopt_reason = licm_hoisted_ ? |
| 3533 ICData::kDeoptHoistedCheckClass : ICData::kDeoptCheckClass; |
| 3534 if (IsNullCheck()) { |
| 3535 Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason); |
| 3536 __ CompareObject(locs()->in(0).reg(), Object::null_object(), PP); |
| 3537 __ b(deopt, EQ); |
| 3538 return; |
| 3539 } |
| 3540 |
| 3541 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || |
| 3542 (unary_checks().NumberOfChecks() > 1)); |
| 3543 Register value = locs()->in(0).reg(); |
| 3544 Register temp = locs()->temp(0).reg(); |
| 3545 Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason); |
| 3546 Label is_ok; |
| 3547 intptr_t cix = 0; |
| 3548 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { |
| 3549 __ tsti(value, kSmiTagMask); |
| 3550 __ b(&is_ok, EQ); |
| 3551 cix++; // Skip first check. |
| 3552 } else { |
| 3553 __ tsti(value, kSmiTagMask); |
| 3554 __ b(deopt, EQ); |
| 3555 } |
| 3556 __ LoadClassId(temp, value); |
| 3557 const intptr_t num_checks = unary_checks().NumberOfChecks(); |
| 3558 for (intptr_t i = cix; i < num_checks; i++) { |
| 3559 ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid); |
| 3560 __ CompareImmediate(temp, unary_checks().GetReceiverClassIdAt(i), PP); |
| 3561 if (i == (num_checks - 1)) { |
| 3562 __ b(deopt, NE); |
| 3563 } else { |
| 3564 __ b(&is_ok, EQ); |
| 3565 } |
| 3566 } |
| 3567 __ Bind(&is_ok); |
| 2468 } | 3568 } |
| 2469 | 3569 |
| 2470 | 3570 |
| 2471 LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const { | 3571 LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const { |
| 2472 UNIMPLEMENTED(); | 3572 const intptr_t kNumInputs = 1; |
| 2473 return NULL; | 3573 const intptr_t kNumTemps = 0; |
| 3574 LocationSummary* summary = |
| 3575 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3576 summary->set_in(0, Location::RequiresRegister()); |
| 3577 return summary; |
| 2474 } | 3578 } |
| 2475 | 3579 |
| 2476 | 3580 |
| 2477 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3581 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2478 UNIMPLEMENTED(); | 3582 Register value = locs()->in(0).reg(); |
| 3583 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckSmi); |
| 3584 __ tsti(value, kSmiTagMask); |
| 3585 __ b(deopt, NE); |
| 2479 } | 3586 } |
| 2480 | 3587 |
| 2481 | 3588 |
| 2482 LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const { | 3589 LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const { |
| 2483 UNIMPLEMENTED(); | 3590 const intptr_t kNumInputs = 2; |
| 2484 return NULL; | 3591 const intptr_t kNumTemps = 0; |
| 3592 LocationSummary* locs = |
| 3593 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3594 locs->set_in(kLengthPos, Location::RegisterOrSmiConstant(length())); |
| 3595 locs->set_in(kIndexPos, Location::RegisterOrSmiConstant(index())); |
| 3596 return locs; |
| 2485 } | 3597 } |
| 2486 | 3598 |
| 2487 | 3599 |
| 2488 void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3600 void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2489 UNIMPLEMENTED(); | 3601 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 3602 ICData::kDeoptCheckArrayBound); |
| 3603 |
| 3604 Location length_loc = locs()->in(kLengthPos); |
| 3605 Location index_loc = locs()->in(kIndexPos); |
| 3606 |
| 3607 if (length_loc.IsConstant() && index_loc.IsConstant()) { |
| 3608 // TODO(srdjan): remove this code once failures are fixed. |
| 3609 if ((Smi::Cast(length_loc.constant()).Value() > |
| 3610 Smi::Cast(index_loc.constant()).Value()) && |
| 3611 (Smi::Cast(index_loc.constant()).Value() >= 0)) { |
| 3612 // This CheckArrayBoundInstr should have been eliminated. |
| 3613 return; |
| 3614 } |
| 3615 ASSERT((Smi::Cast(length_loc.constant()).Value() <= |
| 3616 Smi::Cast(index_loc.constant()).Value()) || |
| 3617 (Smi::Cast(index_loc.constant()).Value() < 0)); |
| 3618 // Unconditionally deoptimize for constant bounds checks because they |
| 3619 // only occur only when index is out-of-bounds. |
| 3620 __ b(deopt); |
| 3621 return; |
| 3622 } |
| 3623 |
| 3624 if (index_loc.IsConstant()) { |
| 3625 Register length = length_loc.reg(); |
| 3626 const Smi& index = Smi::Cast(index_loc.constant()); |
| 3627 __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw()), PP); |
| 3628 __ b(deopt, LS); |
| 3629 } else if (length_loc.IsConstant()) { |
| 3630 const Smi& length = Smi::Cast(length_loc.constant()); |
| 3631 Register index = index_loc.reg(); |
| 3632 __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw()), PP); |
| 3633 __ b(deopt, CS); |
| 3634 } else { |
| 3635 Register length = length_loc.reg(); |
| 3636 Register index = index_loc.reg(); |
| 3637 __ CompareRegisters(index, length); |
| 3638 __ b(deopt, CS); |
| 3639 } |
| 2490 } | 3640 } |
| 2491 | 3641 |
| 2492 | 3642 |
| 2493 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { | 3643 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { |
| 2494 UNIMPLEMENTED(); | 3644 UNIMPLEMENTED(); |
| 2495 return NULL; | 3645 return NULL; |
| 2496 } | 3646 } |
| 2497 | 3647 |
| 2498 | 3648 |
| 2499 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3649 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2635 Location::RequiresRegister(), | 3785 Location::RequiresRegister(), |
| 2636 LocationSummary::kNoCall); | 3786 LocationSummary::kNoCall); |
| 2637 } | 3787 } |
| 2638 | 3788 |
| 2639 | 3789 |
| 2640 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3790 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2641 __ mov(locs()->out(0).reg(), CTX); | 3791 __ mov(locs()->out(0).reg(), CTX); |
| 2642 } | 3792 } |
| 2643 | 3793 |
| 2644 | 3794 |
| 2645 static Condition NegateCondition(Condition condition) { | |
| 2646 switch (condition) { | |
| 2647 case EQ: return NE; | |
| 2648 case NE: return EQ; | |
| 2649 case LT: return GE; | |
| 2650 case LE: return GT; | |
| 2651 case GT: return LE; | |
| 2652 case GE: return LT; | |
| 2653 case CC: return CS; | |
| 2654 case LS: return HI; | |
| 2655 case HI: return LS; | |
| 2656 case CS: return CC; | |
| 2657 default: | |
| 2658 UNREACHABLE(); | |
| 2659 return EQ; | |
| 2660 } | |
| 2661 } | |
| 2662 | |
| 2663 | |
| 2664 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, | |
| 2665 Condition true_condition, | |
| 2666 BranchLabels labels) { | |
| 2667 if (labels.fall_through == labels.false_label) { | |
| 2668 // If the next block is the false successor we will fall through to it. | |
| 2669 __ b(labels.true_label, true_condition); | |
| 2670 } else { | |
| 2671 // If the next block is not the false successor we will branch to it. | |
| 2672 Condition false_condition = NegateCondition(true_condition); | |
| 2673 __ b(labels.false_label, false_condition); | |
| 2674 | |
| 2675 // Fall through or jump to the true successor. | |
| 2676 if (labels.fall_through != labels.true_label) { | |
| 2677 __ b(labels.true_label); | |
| 2678 } | |
| 2679 } | |
| 2680 } | |
| 2681 | |
| 2682 | |
| 2683 LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const { | 3795 LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const { |
| 2684 const intptr_t kNumInputs = 2; | 3796 const intptr_t kNumInputs = 2; |
| 2685 const intptr_t kNumTemps = 0; | 3797 const intptr_t kNumTemps = 0; |
| 2686 if (needs_number_check()) { | 3798 if (needs_number_check()) { |
| 2687 LocationSummary* locs = | 3799 LocationSummary* locs = |
| 2688 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 3800 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 2689 locs->set_in(0, Location::RegisterLocation(R0)); | 3801 locs->set_in(0, Location::RegisterLocation(R0)); |
| 2690 locs->set_in(1, Location::RegisterLocation(R1)); | 3802 locs->set_in(1, Location::RegisterLocation(R1)); |
| 2691 locs->set_out(0, Location::RegisterLocation(R0)); | 3803 locs->set_out(0, Location::RegisterLocation(R0)); |
| 2692 return locs; | 3804 return locs; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2789 compiler->GenerateCall(token_pos(), | 3901 compiler->GenerateCall(token_pos(), |
| 2790 &label, | 3902 &label, |
| 2791 PcDescriptors::kOther, | 3903 PcDescriptors::kOther, |
| 2792 locs()); | 3904 locs()); |
| 2793 __ Drop(ArgumentCount()); // Discard arguments. | 3905 __ Drop(ArgumentCount()); // Discard arguments. |
| 2794 } | 3906 } |
| 2795 | 3907 |
| 2796 } // namespace dart | 3908 } // namespace dart |
| 2797 | 3909 |
| 2798 #endif // defined TARGET_ARCH_ARM64 | 3910 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |