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