| 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 |