OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/bits.h" | 5 #include "src/base/bits.h" |
6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12), | 394 Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12), |
395 g.UseFixed(node->InputAt(1), f14))->MarkAsCall(); | 395 g.UseFixed(node->InputAt(1), f14))->MarkAsCall(); |
396 } | 396 } |
397 | 397 |
398 | 398 |
399 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 399 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
400 MipsOperandGenerator g(this); | 400 MipsOperandGenerator g(this); |
401 Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); | 401 Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); |
402 } | 402 } |
403 | 403 |
404 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 404 |
405 BasicBlock* deoptimization) { | 405 void InstructionSelector::VisitCall(Node* node) { |
406 MipsOperandGenerator g(this); | 406 MipsOperandGenerator g(this); |
407 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 407 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node); |
408 | 408 |
409 FrameStateDescriptor* frame_state_descriptor = NULL; | 409 FrameStateDescriptor* frame_state_descriptor = NULL; |
410 if (descriptor->NeedsFrameState()) { | 410 if (descriptor->NeedsFrameState()) { |
411 frame_state_descriptor = | 411 frame_state_descriptor = |
412 GetFrameStateDescriptor(call->InputAt(descriptor->InputCount())); | 412 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount())); |
413 } | 413 } |
414 | 414 |
415 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 415 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
416 | 416 |
417 // Compute InstructionOperands for inputs and outputs. | 417 // Compute InstructionOperands for inputs and outputs. |
418 InitializeCallBuffer(call, &buffer, true, false); | 418 InitializeCallBuffer(node, &buffer, true, false); |
419 | 419 |
420 // TODO(dcarney): might be possible to use claim/poke instead | 420 // TODO(dcarney): might be possible to use claim/poke instead |
421 // Push any stack arguments. | 421 // Push any stack arguments. |
422 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); | 422 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); |
423 input != buffer.pushed_nodes.rend(); input++) { | 423 input != buffer.pushed_nodes.rend(); input++) { |
424 // TODO(plind): inefficient for MIPS, use MultiPush here. | 424 // TODO(plind): inefficient for MIPS, use MultiPush here. |
425 // - Also need to align the stack. See arm64. | 425 // - Also need to align the stack. See arm64. |
426 // - Maybe combine with arg slot stuff in DirectCEntry stub. | 426 // - Maybe combine with arg slot stuff in DirectCEntry stub. |
427 Emit(kMipsPush, NULL, g.UseRegister(*input)); | 427 Emit(kMipsPush, NULL, g.UseRegister(*input)); |
428 } | 428 } |
(...skipping 11 matching lines...) Expand all Loading... |
440 default: | 440 default: |
441 UNREACHABLE(); | 441 UNREACHABLE(); |
442 return; | 442 return; |
443 } | 443 } |
444 opcode |= MiscField::encode(descriptor->flags()); | 444 opcode |= MiscField::encode(descriptor->flags()); |
445 | 445 |
446 // Emit the call instruction. | 446 // Emit the call instruction. |
447 Instruction* call_instr = | 447 Instruction* call_instr = |
448 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), | 448 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), |
449 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 449 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
450 | |
451 call_instr->MarkAsCall(); | 450 call_instr->MarkAsCall(); |
452 if (deoptimization != NULL) { | |
453 DCHECK(continuation != NULL); | |
454 call_instr->MarkAsControl(); | |
455 } | |
456 } | 451 } |
457 | 452 |
458 | 453 |
459 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | 454 namespace { |
460 FlagsContinuation* cont) { | |
461 VisitBinop(this, node, kMipsAddOvf, cont); | |
462 } | |
463 | |
464 | |
465 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
466 FlagsContinuation* cont) { | |
467 VisitBinop(this, node, kMipsSubOvf, cont); | |
468 } | |
469 | |
470 | 455 |
471 // Shared routine for multiple compare operations. | 456 // Shared routine for multiple compare operations. |
472 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 457 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
473 InstructionOperand* left, InstructionOperand* right, | 458 InstructionOperand* left, InstructionOperand* right, |
474 FlagsContinuation* cont) { | 459 FlagsContinuation* cont) { |
475 MipsOperandGenerator g(selector); | 460 MipsOperandGenerator g(selector); |
476 opcode = cont->Encode(opcode); | 461 opcode = cont->Encode(opcode); |
477 if (cont->IsBranch()) { | 462 if (cont->IsBranch()) { |
478 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), | 463 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), |
479 g.Label(cont->false_block()))->MarkAsControl(); | 464 g.Label(cont->false_block()))->MarkAsControl(); |
480 } else { | 465 } else { |
481 DCHECK(cont->IsSet()); | 466 DCHECK(cont->IsSet()); |
482 // TODO(plind): Revisit and test this path. | 467 // TODO(plind): Revisit and test this path. |
483 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); | 468 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); |
484 } | 469 } |
485 } | 470 } |
486 | 471 |
487 | 472 |
| 473 // Shared routine for multiple float compare operations. |
| 474 void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
| 475 FlagsContinuation* cont) { |
| 476 MipsOperandGenerator g(selector); |
| 477 Node* left = node->InputAt(0); |
| 478 Node* right = node->InputAt(1); |
| 479 VisitCompare(selector, kMipsCmpD, g.UseRegister(left), g.UseRegister(right), |
| 480 cont); |
| 481 } |
| 482 |
| 483 |
488 // Shared routine for multiple word compare operations. | 484 // Shared routine for multiple word compare operations. |
489 static void VisitWordCompare(InstructionSelector* selector, Node* node, | 485 void VisitWordCompare(InstructionSelector* selector, Node* node, |
490 InstructionCode opcode, FlagsContinuation* cont, | 486 InstructionCode opcode, FlagsContinuation* cont, |
491 bool commutative) { | 487 bool commutative) { |
492 MipsOperandGenerator g(selector); | 488 MipsOperandGenerator g(selector); |
493 Node* left = node->InputAt(0); | 489 Node* left = node->InputAt(0); |
494 Node* right = node->InputAt(1); | 490 Node* right = node->InputAt(1); |
495 | 491 |
496 // Match immediates on left or right side of comparison. | 492 // Match immediates on left or right side of comparison. |
497 if (g.CanBeImmediate(right, opcode)) { | 493 if (g.CanBeImmediate(right, opcode)) { |
498 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), | 494 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), |
499 cont); | 495 cont); |
500 } else if (g.CanBeImmediate(left, opcode)) { | 496 } else if (g.CanBeImmediate(left, opcode)) { |
501 if (!commutative) cont->Commute(); | 497 if (!commutative) cont->Commute(); |
502 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), | 498 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), |
503 cont); | 499 cont); |
504 } else { | 500 } else { |
505 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), | 501 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), |
506 cont); | 502 cont); |
507 } | 503 } |
508 } | 504 } |
509 | 505 |
510 | 506 |
511 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { | 507 void VisitWordCompare(InstructionSelector* selector, Node* node, |
512 switch (node->opcode()) { | 508 FlagsContinuation* cont) { |
513 case IrOpcode::kWord32And: | 509 VisitWordCompare(selector, node, kMipsCmp, cont, false); |
514 // TODO(plind): understand the significance of 'IR and' special case. | |
515 return VisitWordCompare(this, node, kMipsTst, cont, true); | |
516 default: | |
517 break; | |
518 } | |
519 | |
520 MipsOperandGenerator g(this); | |
521 // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result | |
522 // in a dedicated tmp register. | |
523 VisitCompare(this, kMipsTst, g.UseRegister(node), g.UseRegister(node), cont); | |
524 } | 510 } |
525 | 511 |
526 | 512 |
527 void InstructionSelector::VisitWord32Compare(Node* node, | 513 void VisitWordTest(InstructionSelector* selector, Node* node, |
528 FlagsContinuation* cont) { | 514 FlagsContinuation* cont) { |
529 VisitWordCompare(this, node, kMipsCmp, cont, false); | 515 MipsOperandGenerator g(selector); |
| 516 // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result |
| 517 // in a dedicated tmp register. |
| 518 VisitCompare(selector, kMipsTst, g.UseRegister(node), g.UseRegister(node), |
| 519 cont); |
| 520 } |
| 521 |
| 522 } // namespace |
| 523 |
| 524 |
| 525 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 526 BasicBlock* fbranch) { |
| 527 MipsOperandGenerator g(this); |
| 528 Node* user = branch; |
| 529 Node* value = branch->InputAt(0); |
| 530 |
| 531 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 532 |
| 533 // If we can fall through to the true block, invert the branch. |
| 534 if (IsNextInAssemblyOrder(tbranch)) { |
| 535 cont.Negate(); |
| 536 cont.SwapBlocks(); |
| 537 } |
| 538 |
| 539 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 540 while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) { |
| 541 Int32BinopMatcher m(value); |
| 542 if (m.right().Is(0)) { |
| 543 user = value; |
| 544 value = m.left().node(); |
| 545 cont.Negate(); |
| 546 } else { |
| 547 break; |
| 548 } |
| 549 } |
| 550 |
| 551 // Try to combine the branch with a comparison. |
| 552 if (CanCover(user, value)) { |
| 553 switch (value->opcode()) { |
| 554 case IrOpcode::kWord32And: |
| 555 // TODO(plind): understand the significance of 'IR and' special case. |
| 556 return VisitWordCompare(this, value, kMipsTst, &cont, true); |
| 557 default: |
| 558 break; |
| 559 } |
| 560 } |
| 561 |
| 562 // Branch could not be combined with a compare, emit compare against 0. |
| 563 return VisitWordTest(this, value, &cont); |
530 } | 564 } |
531 | 565 |
532 | 566 |
533 void InstructionSelector::VisitFloat64Compare(Node* node, | 567 void InstructionSelector::VisitWord32Equal(Node* const node) { |
534 FlagsContinuation* cont) { | 568 Node* const user = node; |
535 MipsOperandGenerator g(this); | 569 FlagsContinuation cont(kEqual, node); |
536 Node* left = node->InputAt(0); | 570 Int32BinopMatcher m(user); |
537 Node* right = node->InputAt(1); | 571 VisitWordCompare(this, node, &cont); |
538 VisitCompare(this, kMipsCmpD, g.UseRegister(left), g.UseRegister(right), | 572 } |
539 cont); | 573 |
| 574 |
| 575 void InstructionSelector::VisitInt32LessThan(Node* node) { |
| 576 FlagsContinuation cont(kSignedLessThan, node); |
| 577 VisitWordCompare(this, node, &cont); |
| 578 } |
| 579 |
| 580 |
| 581 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { |
| 582 FlagsContinuation cont(kSignedLessThanOrEqual, node); |
| 583 VisitWordCompare(this, node, &cont); |
| 584 } |
| 585 |
| 586 |
| 587 void InstructionSelector::VisitUint32LessThan(Node* node) { |
| 588 FlagsContinuation cont(kUnsignedLessThan, node); |
| 589 VisitWordCompare(this, node, &cont); |
| 590 } |
| 591 |
| 592 |
| 593 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { |
| 594 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
| 595 VisitWordCompare(this, node, &cont); |
| 596 } |
| 597 |
| 598 |
| 599 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 600 if (Node* ovf = node->FindProjection(1)) { |
| 601 FlagsContinuation cont(kOverflow, ovf); |
| 602 return VisitBinop(this, node, kMipsAddOvf, &cont); |
| 603 } |
| 604 FlagsContinuation cont; |
| 605 VisitBinop(this, node, kMipsAdd, &cont); |
| 606 } |
| 607 |
| 608 |
| 609 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 610 if (Node* ovf = node->FindProjection(1)) { |
| 611 FlagsContinuation cont(kOverflow, ovf); |
| 612 return VisitBinop(this, node, kMipsSubOvf, &cont); |
| 613 } |
| 614 FlagsContinuation cont; |
| 615 VisitBinop(this, node, kMipsSub, &cont); |
| 616 } |
| 617 |
| 618 |
| 619 void InstructionSelector::VisitFloat64Equal(Node* node) { |
| 620 FlagsContinuation cont(kUnorderedEqual, node); |
| 621 VisitFloat64Compare(this, node, &cont); |
| 622 } |
| 623 |
| 624 |
| 625 void InstructionSelector::VisitFloat64LessThan(Node* node) { |
| 626 FlagsContinuation cont(kUnorderedLessThan, node); |
| 627 VisitFloat64Compare(this, node, &cont); |
| 628 } |
| 629 |
| 630 |
| 631 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
| 632 FlagsContinuation cont(kUnorderedLessThanOrEqual, node); |
| 633 VisitFloat64Compare(this, node, &cont); |
540 } | 634 } |
541 | 635 |
542 } // namespace compiler | 636 } // namespace compiler |
543 } // namespace internal | 637 } // namespace internal |
544 } // namespace v8 | 638 } // namespace v8 |
OLD | NEW |