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 |