Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 case BELOW_EQUAL: return ABOVE; | 319 case BELOW_EQUAL: return ABOVE; |
| 320 case ABOVE: return BELOW_EQUAL; | 320 case ABOVE: return BELOW_EQUAL; |
| 321 case ABOVE_EQUAL: return BELOW; | 321 case ABOVE_EQUAL: return BELOW; |
| 322 default: | 322 default: |
| 323 UNIMPLEMENTED(); | 323 UNIMPLEMENTED(); |
| 324 return EQUAL; | 324 return EQUAL; |
| 325 } | 325 } |
| 326 } | 326 } |
| 327 | 327 |
| 328 | 328 |
| 329 struct BranchLabels { | |
| 330 Label* true_label; | |
| 331 Label* false_label; | |
| 332 Label* fall_through; | |
| 333 }; | |
| 334 | |
| 335 | |
| 329 static void EmitBranchOnValue(FlowGraphCompiler* compiler, | 336 static void EmitBranchOnValue(FlowGraphCompiler* compiler, |
| 330 TargetEntryInstr* true_successor, | 337 bool value, |
| 331 TargetEntryInstr* false_successor, | 338 BranchLabels labels) { |
| 332 bool value) { | 339 if (value && labels.fall_through != labels.true_label) { |
|
Kevin Millikin (Google)
2013/11/07 14:34:09
I've actually gotten used to the extra parens arou
Florian Schneider
2013/11/08 12:00:20
Done.
| |
| 333 if (value && !compiler->CanFallThroughTo(true_successor)) { | 340 __ jmp(labels.true_label); |
| 334 __ jmp(compiler->GetJumpLabel(true_successor)); | 341 } else if (!value && labels.fall_through != labels.false_label) { |
| 335 } else if (!value && !compiler->CanFallThroughTo(false_successor)) { | 342 __ jmp(labels.false_label); |
| 336 __ jmp(compiler->GetJumpLabel(false_successor)); | |
| 337 } | 343 } |
| 338 } | 344 } |
| 339 | 345 |
| 340 | 346 |
| 341 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, | 347 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 342 TargetEntryInstr* true_successor, | 348 Condition true_condition, |
| 343 TargetEntryInstr* false_successor, | 349 BranchLabels labels) { |
| 344 Condition true_condition) { | 350 if (labels.fall_through == labels.false_label) { |
| 345 if (compiler->CanFallThroughTo(false_successor)) { | |
| 346 // If the next block is the false successor, fall through to it. | 351 // If the next block is the false successor, fall through to it. |
| 347 __ j(true_condition, compiler->GetJumpLabel(true_successor)); | 352 __ j(true_condition, labels.true_label); |
| 348 } else { | 353 } else { |
| 349 // If the next block is not the false successor, branch to it. | 354 // If the next block is not the false successor, branch to it. |
| 350 Condition false_condition = NegateCondition(true_condition); | 355 Condition false_condition = NegateCondition(true_condition); |
| 351 __ j(false_condition, compiler->GetJumpLabel(false_successor)); | 356 __ j(false_condition, labels.false_label); |
| 352 | 357 |
| 353 // Fall through or jump to the true successor. | 358 // Fall through or jump to the true successor. |
| 354 if (!compiler->CanFallThroughTo(true_successor)) { | 359 if (labels.fall_through != labels.true_label) { |
| 355 __ jmp(compiler->GetJumpLabel(true_successor)); | 360 __ jmp(labels.true_label); |
| 356 } | 361 } |
| 357 } | 362 } |
| 358 } | 363 } |
| 359 | 364 |
| 360 | 365 |
| 361 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 366 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 362 const LocationSummary& locs, | 367 const LocationSummary& locs, |
| 363 Token::Kind kind, | 368 Token::Kind kind, |
| 364 BranchInstr* branch) { | 369 BranchLabels labels) { |
| 365 Location left = locs.in(0); | 370 Location left = locs.in(0); |
| 366 Location right = locs.in(1); | 371 Location right = locs.in(1); |
| 367 ASSERT(!left.IsConstant() || !right.IsConstant()); | 372 ASSERT(!left.IsConstant() || !right.IsConstant()); |
| 368 | 373 |
| 369 Condition true_condition = TokenKindToSmiCondition(kind); | 374 Condition true_condition = TokenKindToSmiCondition(kind); |
| 370 | 375 |
| 371 if (left.IsConstant()) { | 376 if (left.IsConstant()) { |
| 372 __ CompareObject(right.reg(), left.constant()); | 377 __ CompareObject(right.reg(), left.constant()); |
| 373 true_condition = FlipCondition(true_condition); | 378 true_condition = FlipCondition(true_condition); |
| 374 } else if (right.IsConstant()) { | 379 } else if (right.IsConstant()) { |
| 375 __ CompareObject(left.reg(), right.constant()); | 380 __ CompareObject(left.reg(), right.constant()); |
| 376 } else if (right.IsStackSlot()) { | 381 } else if (right.IsStackSlot()) { |
| 377 __ cmpl(left.reg(), right.ToStackSlotAddress()); | 382 __ cmpl(left.reg(), right.ToStackSlotAddress()); |
| 378 } else { | 383 } else { |
| 379 __ cmpl(left.reg(), right.reg()); | 384 __ cmpl(left.reg(), right.reg()); |
| 380 } | 385 } |
| 381 | 386 EmitBranchOnCondition(compiler, true_condition, labels); |
| 382 if (branch != NULL) { | |
| 383 EmitBranchOnCondition(compiler, | |
| 384 branch->true_successor(), | |
| 385 branch->false_successor(), | |
| 386 true_condition); | |
| 387 } else { | |
| 388 Register result = locs.out().reg(); | |
| 389 Label done, is_true; | |
| 390 __ j(true_condition, &is_true); | |
| 391 __ LoadObject(result, Bool::False()); | |
| 392 __ jmp(&done); | |
| 393 __ Bind(&is_true); | |
| 394 __ LoadObject(result, Bool::True()); | |
| 395 __ Bind(&done); | |
| 396 } | |
| 397 } | 387 } |
| 398 | 388 |
| 399 | 389 |
| 400 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, | 390 static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler, |
| 401 Label* overflow, | 391 Label* overflow, |
| 402 XmmRegister result, | 392 XmmRegister result, |
| 403 Register tmp) { | 393 Register tmp) { |
| 404 // Compare upper half. | 394 // Compare upper half. |
| 405 Label check_lower, done; | 395 Label check_lower, done; |
| 406 __ pextrd(tmp, result, Immediate(1)); | 396 __ pextrd(tmp, result, Immediate(1)); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 434 default: | 424 default: |
| 435 UNREACHABLE(); | 425 UNREACHABLE(); |
| 436 return OVERFLOW; | 426 return OVERFLOW; |
| 437 } | 427 } |
| 438 } | 428 } |
| 439 | 429 |
| 440 | 430 |
| 441 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | 431 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| 442 const LocationSummary& locs, | 432 const LocationSummary& locs, |
| 443 Token::Kind kind, | 433 Token::Kind kind, |
| 444 BranchInstr* branch) { | 434 BranchLabels labels) { |
| 445 ASSERT(Token::IsEqualityOperator(kind)); | 435 ASSERT(Token::IsEqualityOperator(kind)); |
| 446 XmmRegister left = locs.in(0).fpu_reg(); | 436 XmmRegister left = locs.in(0).fpu_reg(); |
| 447 XmmRegister right = locs.in(1).fpu_reg(); | 437 XmmRegister right = locs.in(1).fpu_reg(); |
| 448 Register temp = locs.temp(0).reg(); | 438 Register temp = locs.temp(0).reg(); |
| 449 __ movaps(XMM0, left); | 439 __ movaps(XMM0, left); |
| 450 __ pcmpeqq(XMM0, right); | 440 __ pcmpeqq(XMM0, right); |
| 451 __ movd(temp, XMM0); | 441 __ movd(temp, XMM0); |
| 452 | 442 |
| 453 Condition true_condition = TokenKindToMintCondition(kind); | 443 Condition true_condition = TokenKindToMintCondition(kind); |
| 454 __ cmpl(temp, Immediate(-1)); | 444 __ cmpl(temp, Immediate(-1)); |
| 455 | 445 EmitBranchOnCondition(compiler, true_condition, labels); |
| 456 if (branch != NULL) { | |
| 457 EmitBranchOnCondition(compiler, | |
| 458 branch->true_successor(), | |
| 459 branch->false_successor(), | |
| 460 true_condition); | |
| 461 } else { | |
| 462 Register result = locs.out().reg(); | |
| 463 Label done, is_true; | |
| 464 __ j(true_condition, &is_true); | |
| 465 __ LoadObject(result, Bool::False()); | |
| 466 __ jmp(&done); | |
| 467 __ Bind(&is_true); | |
| 468 __ LoadObject(result, Bool::True()); | |
| 469 __ Bind(&done); | |
| 470 } | |
| 471 } | 446 } |
| 472 | 447 |
| 473 | 448 |
| 474 static void EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, | 449 static void EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
| 475 const LocationSummary& locs, | 450 const LocationSummary& locs, |
| 476 Token::Kind kind, | 451 Token::Kind kind, |
| 477 BranchInstr* branch) { | 452 BranchLabels labels) { |
| 478 XmmRegister left = locs.in(0).fpu_reg(); | 453 XmmRegister left = locs.in(0).fpu_reg(); |
| 479 XmmRegister right = locs.in(1).fpu_reg(); | 454 XmmRegister right = locs.in(1).fpu_reg(); |
| 480 Register left_tmp = locs.temp(0).reg(); | 455 Register left_tmp = locs.temp(0).reg(); |
| 481 Register right_tmp = locs.temp(1).reg(); | 456 Register right_tmp = locs.temp(1).reg(); |
| 482 Register result = branch == NULL ? locs.out().reg() : kNoRegister; | |
| 483 | 457 |
| 484 Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW; | 458 Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW; |
| 485 switch (kind) { | 459 switch (kind) { |
| 486 case Token::kLT: | 460 case Token::kLT: |
| 487 hi_cond = LESS; | 461 hi_cond = LESS; |
| 488 lo_cond = BELOW; | 462 lo_cond = BELOW; |
| 489 break; | 463 break; |
| 490 case Token::kGT: | 464 case Token::kGT: |
| 491 hi_cond = GREATER; | 465 hi_cond = GREATER; |
| 492 lo_cond = ABOVE; | 466 lo_cond = ABOVE; |
| 493 break; | 467 break; |
| 494 case Token::kLTE: | 468 case Token::kLTE: |
| 495 hi_cond = LESS; | 469 hi_cond = LESS; |
| 496 lo_cond = BELOW_EQUAL; | 470 lo_cond = BELOW_EQUAL; |
| 497 break; | 471 break; |
| 498 case Token::kGTE: | 472 case Token::kGTE: |
| 499 hi_cond = GREATER; | 473 hi_cond = GREATER; |
| 500 lo_cond = ABOVE_EQUAL; | 474 lo_cond = ABOVE_EQUAL; |
| 501 break; | 475 break; |
| 502 default: | 476 default: |
| 503 break; | 477 break; |
| 504 } | 478 } |
| 505 ASSERT(hi_cond != OVERFLOW && lo_cond != OVERFLOW); | 479 ASSERT(hi_cond != OVERFLOW && lo_cond != OVERFLOW); |
| 506 Label is_true, is_false; | 480 Label is_true, is_false; |
| 507 // Compare upper halves first. | 481 // Compare upper halves first. |
| 508 __ pextrd(left_tmp, left, Immediate(1)); | 482 __ pextrd(left_tmp, left, Immediate(1)); |
| 509 __ pextrd(right_tmp, right, Immediate(1)); | 483 __ pextrd(right_tmp, right, Immediate(1)); |
| 510 __ cmpl(left_tmp, right_tmp); | 484 __ cmpl(left_tmp, right_tmp); |
| 511 if (branch != NULL) { | 485 __ j(hi_cond, labels.true_label); |
| 512 __ j(hi_cond, compiler->GetJumpLabel(branch->true_successor())); | 486 __ j(FlipCondition(hi_cond), labels.false_label); |
| 513 __ j(FlipCondition(hi_cond), | |
| 514 compiler->GetJumpLabel(branch->false_successor())); | |
| 515 } else { | |
| 516 __ j(hi_cond, &is_true); | |
| 517 __ j(FlipCondition(hi_cond), &is_false); | |
| 518 } | |
| 519 | 487 |
| 520 // If upper is equal, compare lower half. | 488 // If upper is equal, compare lower half. |
| 521 __ pextrd(left_tmp, left, Immediate(0)); | 489 __ pextrd(left_tmp, left, Immediate(0)); |
| 522 __ pextrd(right_tmp, right, Immediate(0)); | 490 __ pextrd(right_tmp, right, Immediate(0)); |
| 523 __ cmpl(left_tmp, right_tmp); | 491 __ cmpl(left_tmp, right_tmp); |
| 524 if (branch != NULL) { | 492 EmitBranchOnCondition(compiler, lo_cond, labels); |
| 525 EmitBranchOnCondition(compiler, | |
| 526 branch->true_successor(), | |
| 527 branch->false_successor(), | |
| 528 lo_cond); | |
| 529 } else { | |
| 530 Label done; | |
| 531 __ j(lo_cond, &is_true); | |
| 532 __ Bind(&is_false); | |
| 533 __ LoadObject(result, Bool::False()); | |
| 534 __ jmp(&done); | |
| 535 __ Bind(&is_true); | |
| 536 __ LoadObject(result, Bool::True()); | |
| 537 __ Bind(&done); | |
| 538 } | |
| 539 } | 493 } |
| 540 | 494 |
| 541 | 495 |
| 542 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 496 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 543 switch (kind) { | 497 switch (kind) { |
| 544 case Token::kEQ: return EQUAL; | 498 case Token::kEQ: return EQUAL; |
| 545 case Token::kNE: return NOT_EQUAL; | 499 case Token::kNE: return NOT_EQUAL; |
| 546 case Token::kLT: return BELOW; | 500 case Token::kLT: return BELOW; |
| 547 case Token::kGT: return ABOVE; | 501 case Token::kGT: return ABOVE; |
| 548 case Token::kLTE: return BELOW_EQUAL; | 502 case Token::kLTE: return BELOW_EQUAL; |
| 549 case Token::kGTE: return ABOVE_EQUAL; | 503 case Token::kGTE: return ABOVE_EQUAL; |
| 550 default: | 504 default: |
| 551 UNREACHABLE(); | 505 UNREACHABLE(); |
| 552 return OVERFLOW; | 506 return OVERFLOW; |
| 553 } | 507 } |
| 554 } | 508 } |
| 555 | 509 |
| 556 | 510 |
| 557 static void EmitDoubleCompareBranch(FlowGraphCompiler* compiler, | 511 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 558 Condition true_condition, | 512 const LocationSummary& locs, |
| 559 FpuRegister left, | 513 Token::Kind kind, |
| 560 FpuRegister right, | 514 BranchLabels labels) { |
| 561 BranchInstr* branch) { | 515 XmmRegister left = locs.in(0).fpu_reg(); |
| 562 ASSERT(branch != NULL); | 516 XmmRegister right = locs.in(1).fpu_reg(); |
| 517 | |
| 563 __ comisd(left, right); | 518 __ comisd(left, right); |
| 564 BlockEntryInstr* nan_result = (true_condition == NOT_EQUAL) ? | 519 |
| 565 branch->true_successor() : branch->false_successor(); | 520 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 566 __ j(PARITY_EVEN, compiler->GetJumpLabel(nan_result)); | 521 Label* nan_result = (true_condition == NOT_EQUAL) |
| 567 EmitBranchOnCondition(compiler, | 522 ? labels.true_label : labels.false_label; |
| 568 branch->true_successor(), | 523 __ j(PARITY_EVEN, nan_result); |
| 569 branch->false_successor(), | 524 EmitBranchOnCondition(compiler, true_condition, labels); |
| 570 true_condition); | |
| 571 } | 525 } |
| 572 | 526 |
| 573 | 527 |
| 528 static BranchLabels CreateBranchLabels(FlowGraphCompiler* compiler, | |
| 529 BranchInstr* branch) { | |
| 530 Label* true_label = compiler->GetJumpLabel(branch->true_successor()); | |
| 531 Label* false_label = compiler->GetJumpLabel(branch->false_successor()); | |
| 532 Label* fall_through = compiler->CanFallThroughTo(branch->true_successor()) | |
|
Kevin Millikin (Google)
2013/11/07 14:34:09
Hmmm, that's kind of ugly. What about a function
Florian Schneider
2013/11/08 12:00:20
Agreed. CanFallThroughTo uses next_nonempty_label
| |
| 533 ? true_label : compiler->CanFallThroughTo(branch->false_successor()) | |
| 534 ? false_label : NULL; | |
| 535 BranchLabels result = { true_label, false_label, fall_through }; | |
| 536 return result; | |
| 537 } | |
| 574 | 538 |
| 575 static void EmitDoubleCompareBool(FlowGraphCompiler* compiler, | 539 |
| 576 Condition true_condition, | 540 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 577 FpuRegister left, | 541 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 578 FpuRegister right, | 542 |
| 579 Register result) { | 543 Label is_true, is_false; |
| 580 __ comisd(left, right); | 544 BranchLabels labels = { &is_true, &is_false, &is_false }; |
| 581 Label is_false, is_true, done; | 545 |
| 582 // x == NaN -> false, x != NaN -> true. | 546 if (operation_cid() == kSmiCid) { |
| 583 Label* nan_label = (true_condition == NOT_EQUAL) ? &is_true : &is_false; | 547 EmitSmiComparisonOp(compiler, *locs(), kind(), labels); |
| 584 __ j(PARITY_EVEN, nan_label, Assembler::kNearJump); | 548 } else if (operation_cid() == kMintCid) { |
| 585 __ j(true_condition, &is_true, Assembler::kNearJump); | 549 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), labels); |
| 550 } else { | |
| 551 ASSERT(operation_cid() == kDoubleCid); | |
| 552 EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); | |
| 553 } | |
| 554 Register result = locs()->out().reg(); | |
| 555 Label done; | |
| 586 __ Bind(&is_false); | 556 __ Bind(&is_false); |
| 587 __ LoadObject(result, Bool::False()); | 557 __ LoadObject(result, Bool::False()); |
| 588 __ jmp(&done); | 558 __ jmp(&done, Assembler::kNearJump); |
| 589 __ Bind(&is_true); | 559 __ Bind(&is_true); |
| 590 __ LoadObject(result, Bool::True()); | 560 __ LoadObject(result, Bool::True()); |
| 591 __ Bind(&done); | 561 __ Bind(&done); |
| 592 } | 562 } |
| 593 | 563 |
| 594 | 564 |
| 595 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 565 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 596 const LocationSummary& locs, | 566 BranchInstr* branch) { |
| 597 Token::Kind kind, | 567 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 598 BranchInstr* branch) { | |
| 599 XmmRegister left = locs.in(0).fpu_reg(); | |
| 600 XmmRegister right = locs.in(1).fpu_reg(); | |
| 601 | 568 |
| 602 Condition true_condition = TokenKindToDoubleCondition(kind); | 569 BranchLabels labels = CreateBranchLabels(compiler, branch); |
| 603 if (branch != NULL) { | 570 |
| 604 EmitDoubleCompareBranch(compiler, true_condition, left, right, branch); | 571 if (operation_cid() == kSmiCid) { |
| 572 EmitSmiComparisonOp(compiler, *locs(), kind(), labels); | |
| 573 } else if (operation_cid() == kMintCid) { | |
| 574 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), labels); | |
| 605 } else { | 575 } else { |
| 606 EmitDoubleCompareBool(compiler, true_condition, | 576 ASSERT(operation_cid() == kDoubleCid); |
| 607 left, right, locs.out().reg()); | 577 EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); |
| 608 } | 578 } |
| 609 } | 579 } |
| 610 | 580 |
| 611 | 581 |
| 612 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 613 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | |
| 614 BranchInstr* kNoBranch = NULL; | |
| 615 if (operation_cid() == kSmiCid) { | |
| 616 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); | |
| 617 return; | |
| 618 } | |
| 619 if (operation_cid() == kMintCid) { | |
| 620 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); | |
| 621 return; | |
| 622 } | |
| 623 if (operation_cid() == kDoubleCid) { | |
| 624 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); | |
| 625 return; | |
| 626 } | |
| 627 UNREACHABLE(); | |
| 628 } | |
| 629 | |
| 630 | |
| 631 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | |
| 632 BranchInstr* branch) { | |
| 633 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | |
| 634 if (operation_cid() == kSmiCid) { | |
| 635 // Deoptimizes if both arguments not Smi. | |
| 636 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | |
| 637 return; | |
| 638 } | |
| 639 if (operation_cid() == kMintCid) { | |
| 640 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); | |
| 641 return; | |
| 642 } | |
| 643 if (operation_cid() == kDoubleCid) { | |
| 644 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | |
| 645 return; | |
| 646 } | |
| 647 UNREACHABLE(); | |
| 648 } | |
| 649 | |
| 650 | |
| 651 LocationSummary* TestSmiInstr::MakeLocationSummary() const { | 582 LocationSummary* TestSmiInstr::MakeLocationSummary() const { |
| 652 const intptr_t kNumInputs = 2; | 583 const intptr_t kNumInputs = 2; |
| 653 const intptr_t kNumTemps = 0; | 584 const intptr_t kNumTemps = 0; |
| 654 LocationSummary* locs = | 585 LocationSummary* locs = |
| 655 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 586 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 656 locs->set_in(0, Location::RequiresRegister()); | 587 locs->set_in(0, Location::RequiresRegister()); |
| 657 // Only one input can be a constant operand. The case of two constant | 588 // Only one input can be a constant operand. The case of two constant |
| 658 // operands should be handled by constant propagation. | 589 // operands should be handled by constant propagation. |
| 659 locs->set_in(1, Location::RegisterOrConstant(right())); | 590 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 660 return locs; | 591 return locs; |
| 661 } | 592 } |
| 662 | 593 |
| 663 | 594 |
| 664 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 595 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 665 // Never emitted outside of the BranchInstr. | 596 // Never emitted outside of the BranchInstr. |
| 666 UNREACHABLE(); | 597 UNREACHABLE(); |
| 667 } | 598 } |
| 668 | 599 |
| 669 | 600 |
| 670 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 601 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 671 BranchInstr* branch) { | 602 BranchInstr* branch) { |
| 672 Condition branch_condition = (kind() == Token::kNE) ? NOT_ZERO : ZERO; | 603 BranchLabels labels = CreateBranchLabels(compiler, branch); |
| 604 | |
| 605 Condition true_condition = (kind() == Token::kNE) ? NOT_ZERO : ZERO; | |
| 673 Register left = locs()->in(0).reg(); | 606 Register left = locs()->in(0).reg(); |
| 674 Location right = locs()->in(1); | 607 Location right = locs()->in(1); |
| 675 if (right.IsConstant()) { | 608 if (right.IsConstant()) { |
| 676 ASSERT(right.constant().IsSmi()); | 609 ASSERT(right.constant().IsSmi()); |
| 677 const int32_t imm = | 610 const int32_t imm = |
| 678 reinterpret_cast<int32_t>(right.constant().raw()); | 611 reinterpret_cast<int32_t>(right.constant().raw()); |
| 679 __ testl(left, Immediate(imm)); | 612 __ testl(left, Immediate(imm)); |
| 680 } else { | 613 } else { |
| 681 __ testl(left, right.reg()); | 614 __ testl(left, right.reg()); |
| 682 } | 615 } |
| 683 EmitBranchOnCondition(compiler, | 616 EmitBranchOnCondition(compiler, true_condition, labels); |
| 684 branch->true_successor(), | |
| 685 branch->false_successor(), | |
| 686 branch_condition); | |
| 687 } | 617 } |
| 688 | 618 |
| 689 | 619 |
| 690 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 620 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 691 const intptr_t kNumInputs = 2; | 621 const intptr_t kNumInputs = 2; |
| 692 const intptr_t kNumTemps = 0; | 622 const intptr_t kNumTemps = 0; |
| 693 if (operation_cid() == kMintCid) { | 623 if (operation_cid() == kMintCid) { |
| 694 const intptr_t kNumTemps = 2; | 624 const intptr_t kNumTemps = 2; |
| 695 LocationSummary* locs = | 625 LocationSummary* locs = |
| 696 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 626 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 717 // operands should be handled by constant propagation. | 647 // operands should be handled by constant propagation. |
| 718 summary->set_in(1, summary->in(0).IsConstant() | 648 summary->set_in(1, summary->in(0).IsConstant() |
| 719 ? Location::RequiresRegister() | 649 ? Location::RequiresRegister() |
| 720 : Location::RegisterOrConstant(right())); | 650 : Location::RegisterOrConstant(right())); |
| 721 summary->set_out(Location::RequiresRegister()); | 651 summary->set_out(Location::RequiresRegister()); |
| 722 return summary; | 652 return summary; |
| 723 } | 653 } |
| 724 | 654 |
| 725 | 655 |
| 726 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 656 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 657 Label is_true, is_false; | |
| 658 BranchLabels labels = { &is_true, &is_false, &is_false }; | |
| 659 | |
| 727 if (operation_cid() == kSmiCid) { | 660 if (operation_cid() == kSmiCid) { |
| 728 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL); | 661 EmitSmiComparisonOp(compiler, *locs(), kind(), labels); |
| 729 return; | 662 } else if (operation_cid() == kMintCid) { |
| 663 EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), labels); | |
| 664 } else { | |
| 665 ASSERT(operation_cid() == kDoubleCid); | |
| 666 EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); | |
| 730 } | 667 } |
| 731 if (operation_cid() == kMintCid) { | 668 Register result = locs()->out().reg(); |
| 732 EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), NULL); | 669 Label done; |
| 733 return; | 670 __ Bind(&is_false); |
| 734 } | 671 __ LoadObject(result, Bool::False()); |
| 735 ASSERT(operation_cid() == kDoubleCid); | 672 __ jmp(&done, Assembler::kNearJump); |
| 736 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL); | 673 __ Bind(&is_true); |
| 674 __ LoadObject(result, Bool::True()); | |
| 675 __ Bind(&done); | |
| 737 } | 676 } |
| 738 | 677 |
| 739 | 678 |
| 740 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 679 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 741 BranchInstr* branch) { | 680 BranchInstr* branch) { |
| 681 BranchLabels labels = CreateBranchLabels(compiler, branch); | |
| 682 | |
| 742 if (operation_cid() == kSmiCid) { | 683 if (operation_cid() == kSmiCid) { |
| 743 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | 684 EmitSmiComparisonOp(compiler, *locs(), kind(), labels); |
| 744 return; | 685 } else if (operation_cid() == kMintCid) { |
| 686 EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), labels); | |
| 687 } else { | |
| 688 ASSERT(operation_cid() == kDoubleCid); | |
| 689 EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); | |
| 745 } | 690 } |
| 746 if (operation_cid() == kMintCid) { | |
| 747 EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), branch); | |
| 748 return; | |
| 749 } | |
| 750 ASSERT(operation_cid() == kDoubleCid); | |
| 751 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | |
| 752 } | 691 } |
| 753 | 692 |
| 754 | 693 |
| 755 LocationSummary* NativeCallInstr::MakeLocationSummary() const { | 694 LocationSummary* NativeCallInstr::MakeLocationSummary() const { |
| 756 const intptr_t kNumInputs = 0; | 695 const intptr_t kNumInputs = 0; |
| 757 const intptr_t kNumTemps = 3; | 696 const intptr_t kNumTemps = 3; |
| 758 LocationSummary* locs = | 697 LocationSummary* locs = |
| 759 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 698 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 760 locs->set_temp(0, Location::RegisterLocation(EAX)); | 699 locs->set_temp(0, Location::RegisterLocation(EAX)); |
| 761 locs->set_temp(1, Location::RegisterLocation(ECX)); | 700 locs->set_temp(1, Location::RegisterLocation(ECX)); |
| (...skipping 3887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4649 const intptr_t kNumTemps = 0; | 4588 const intptr_t kNumTemps = 0; |
| 4650 LocationSummary* locs = | 4589 LocationSummary* locs = |
| 4651 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 4590 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 4652 locs->set_in(0, Location::RegisterOrConstant(left())); | 4591 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 4653 locs->set_in(1, Location::RegisterOrConstant(right())); | 4592 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 4654 locs->set_out(Location::RequiresRegister()); | 4593 locs->set_out(Location::RequiresRegister()); |
| 4655 return locs; | 4594 return locs; |
| 4656 } | 4595 } |
| 4657 | 4596 |
| 4658 | 4597 |
| 4598 static void EmitStrictComparison(FlowGraphCompiler* compiler, | |
| 4599 StrictCompareInstr* compare, | |
| 4600 BranchLabels labels) { | |
| 4601 LocationSummary* locs = compare->locs(); | |
| 4602 bool needs_number_check = compare->needs_number_check(); | |
| 4603 intptr_t token_pos = compare->token_pos(); | |
| 4604 Token::Kind kind = compare->kind(); | |
| 4605 Location left = locs->in(0); | |
| 4606 Location right = locs->in(1); | |
| 4607 if (left.IsConstant() && right.IsConstant()) { | |
| 4608 // TODO(vegorov): should be eliminated earlier by constant propagation. | |
| 4609 const bool result = (kind == Token::kEQ_STRICT) ? | |
| 4610 left.constant().raw() == right.constant().raw() : | |
| 4611 left.constant().raw() != right.constant().raw(); | |
| 4612 EmitBranchOnValue(compiler, result, labels); | |
| 4613 return; | |
| 4614 } | |
| 4615 if (left.IsConstant()) { | |
| 4616 compiler->EmitEqualityRegConstCompare(right.reg(), | |
| 4617 left.constant(), | |
| 4618 needs_number_check, | |
| 4619 token_pos); | |
| 4620 } else if (right.IsConstant()) { | |
| 4621 compiler->EmitEqualityRegConstCompare(left.reg(), | |
| 4622 right.constant(), | |
| 4623 needs_number_check, | |
| 4624 token_pos); | |
| 4625 } else { | |
| 4626 compiler->EmitEqualityRegRegCompare(left.reg(), | |
| 4627 right.reg(), | |
| 4628 needs_number_check, | |
| 4629 token_pos); | |
| 4630 } | |
| 4631 Condition true_condition = (kind == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | |
| 4632 EmitBranchOnCondition(compiler, true_condition, labels); | |
| 4633 } | |
| 4634 | |
| 4635 | |
| 4659 // Special code for numbers (compare values instead of references.) | 4636 // Special code for numbers (compare values instead of references.) |
| 4660 void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4637 void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 4661 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); | 4638 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 4662 Location left = locs()->in(0); | 4639 |
| 4663 Location right = locs()->in(1); | 4640 Label is_true, is_false; |
| 4664 if (left.IsConstant() && right.IsConstant()) { | 4641 BranchLabels labels = { &is_true, &is_false, &is_false }; |
| 4665 // TODO(vegorov): should be eliminated earlier by constant propagation. | 4642 |
| 4666 const bool result = (kind() == Token::kEQ_STRICT) ? | 4643 EmitStrictComparison(compiler, this, labels); |
| 4667 left.constant().raw() == right.constant().raw() : | |
| 4668 left.constant().raw() != right.constant().raw(); | |
| 4669 __ LoadObject(locs()->out().reg(), Bool::Get(result)); | |
| 4670 return; | |
| 4671 } | |
| 4672 if (left.IsConstant()) { | |
| 4673 compiler->EmitEqualityRegConstCompare(right.reg(), | |
| 4674 left.constant(), | |
| 4675 needs_number_check(), | |
| 4676 token_pos()); | |
| 4677 } else if (right.IsConstant()) { | |
| 4678 compiler->EmitEqualityRegConstCompare(left.reg(), | |
| 4679 right.constant(), | |
| 4680 needs_number_check(), | |
| 4681 token_pos()); | |
| 4682 } else { | |
| 4683 compiler->EmitEqualityRegRegCompare(left.reg(), | |
| 4684 right.reg(), | |
| 4685 needs_number_check(), | |
| 4686 token_pos()); | |
| 4687 } | |
| 4688 | 4644 |
| 4689 Register result = locs()->out().reg(); | 4645 Register result = locs()->out().reg(); |
| 4690 Label load_true, done; | 4646 Label done; |
| 4691 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | 4647 __ Bind(&is_false); |
| 4692 __ j(true_condition, &load_true, Assembler::kNearJump); | |
| 4693 __ LoadObject(result, Bool::False()); | 4648 __ LoadObject(result, Bool::False()); |
| 4694 __ jmp(&done, Assembler::kNearJump); | 4649 __ jmp(&done, Assembler::kNearJump); |
| 4695 __ Bind(&load_true); | 4650 __ Bind(&is_true); |
| 4696 __ LoadObject(result, Bool::True()); | 4651 __ LoadObject(result, Bool::True()); |
| 4697 __ Bind(&done); | 4652 __ Bind(&done); |
| 4698 } | 4653 } |
| 4699 | 4654 |
| 4700 | 4655 |
| 4701 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 4656 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 4702 BranchInstr* branch) { | 4657 BranchInstr* branch) { |
| 4703 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); | 4658 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 4704 Location left = locs()->in(0); | |
| 4705 Location right = locs()->in(1); | |
| 4706 if (left.IsConstant() && right.IsConstant()) { | |
| 4707 // TODO(vegorov): should be eliminated earlier by constant propagation. | |
| 4708 const bool result = (kind() == Token::kEQ_STRICT) ? | |
| 4709 left.constant().raw() == right.constant().raw() : | |
| 4710 left.constant().raw() != right.constant().raw(); | |
| 4711 EmitBranchOnValue(compiler, | |
| 4712 branch->true_successor(), | |
| 4713 branch->false_successor(), | |
| 4714 result); | |
| 4715 return; | |
| 4716 } | |
| 4717 if (left.IsConstant()) { | |
| 4718 compiler->EmitEqualityRegConstCompare(right.reg(), | |
| 4719 left.constant(), | |
| 4720 needs_number_check(), | |
| 4721 token_pos()); | |
| 4722 } else if (right.IsConstant()) { | |
| 4723 compiler->EmitEqualityRegConstCompare(left.reg(), | |
| 4724 right.constant(), | |
| 4725 needs_number_check(), | |
| 4726 token_pos()); | |
| 4727 } else { | |
| 4728 compiler->EmitEqualityRegRegCompare(left.reg(), | |
| 4729 right.reg(), | |
| 4730 needs_number_check(), | |
| 4731 token_pos()); | |
| 4732 } | |
| 4733 | 4659 |
| 4734 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | 4660 BranchLabels labels = CreateBranchLabels(compiler, branch); |
| 4735 EmitBranchOnCondition(compiler, | 4661 |
| 4736 branch->true_successor(), | 4662 EmitStrictComparison(compiler, this, labels); |
| 4737 branch->false_successor(), | |
| 4738 true_condition); | |
| 4739 } | 4663 } |
| 4740 | 4664 |
| 4741 | 4665 |
| 4742 // Detect pattern when one value is zero and another is a power of 2. | 4666 // Detect pattern when one value is zero and another is a power of 2. |
| 4743 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { | 4667 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { |
| 4744 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || | 4668 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || |
| 4745 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); | 4669 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); |
| 4746 } | 4670 } |
| 4747 | 4671 |
| 4748 | 4672 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4944 PcDescriptors::kOther, | 4868 PcDescriptors::kOther, |
| 4945 locs()); | 4869 locs()); |
| 4946 __ Drop(2); // Discard type arguments and receiver. | 4870 __ Drop(2); // Discard type arguments and receiver. |
| 4947 } | 4871 } |
| 4948 | 4872 |
| 4949 } // namespace dart | 4873 } // namespace dart |
| 4950 | 4874 |
| 4951 #undef __ | 4875 #undef __ |
| 4952 | 4876 |
| 4953 #endif // defined TARGET_ARCH_IA32 | 4877 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |