Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceTargetLowering.cpp - Basic lowering implementation --===// | 1 //===- subzero/src/IceTargetLowering.cpp - Basic lowering implementation --===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// \brief Implements the skeleton of the TargetLowering class. | 11 /// \brief Implements the skeleton of the TargetLowering class. |
| 12 /// | 12 /// |
| 13 /// Specifically this invokes the appropriate lowering method for a given | 13 /// Specifically this invokes the appropriate lowering method for a given |
| 14 /// instruction kind and driving global register allocation. It also implements | 14 /// instruction kind and driving global register allocation. It also implements |
| 15 /// the non-deleted instruction iteration in LoweringContext. | 15 /// the non-deleted instruction iteration in LoweringContext. |
| 16 /// | 16 /// |
| 17 //===----------------------------------------------------------------------===// | 17 //===----------------------------------------------------------------------===// |
| 18 | 18 |
| 19 #include "IceTargetLowering.h" | 19 #include "IceTargetLowering.h" |
| 20 | 20 |
| 21 #include "IceBitVector.h" | 21 #include "IceBitVector.h" |
| 22 #include "IceCfg.h" // setError() | 22 #include "IceCfg.h" // setError() |
| 23 #include "IceCfgNode.h" | 23 #include "IceCfgNode.h" |
| 24 #include "IceGlobalContext.h" | 24 #include "IceGlobalContext.h" |
| 25 #include "IceGlobalInits.h" | 25 #include "IceGlobalInits.h" |
| 26 #include "IceInstVarIter.h" | 26 #include "IceInstVarIter.h" |
| 27 #include "IceLiveness.h" | |
| 27 #include "IceOperand.h" | 28 #include "IceOperand.h" |
| 28 #include "IceRegAlloc.h" | 29 #include "IceRegAlloc.h" |
| 29 | 30 |
| 30 #include <string> | 31 #include <string> |
| 31 #include <vector> | 32 #include <vector> |
| 32 | 33 |
| 33 #define TARGET_LOWERING_CLASS_FOR(t) Target_##t | 34 #define TARGET_LOWERING_CLASS_FOR(t) Target_##t |
| 34 | 35 |
| 35 // We prevent target-specific implementation details from leaking outside their | 36 // We prevent target-specific implementation details from leaking outside their |
| 36 // implementations by forbidding #include of target-specific header files | 37 // implementations by forbidding #include of target-specific header files |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 LinearScan.scan(RegMask, getFlags().getRandomizeRegisterAllocation()); | 505 LinearScan.scan(RegMask, getFlags().getRandomizeRegisterAllocation()); |
| 505 if (!LinearScan.hasEvictions()) | 506 if (!LinearScan.hasEvictions()) |
| 506 Repeat = false; | 507 Repeat = false; |
| 507 Kind = RAK_SecondChance; | 508 Kind = RAK_SecondChance; |
| 508 } while (Repeat); | 509 } while (Repeat); |
| 509 // TODO(stichnot): Run the register allocator one more time to do stack slot | 510 // TODO(stichnot): Run the register allocator one more time to do stack slot |
| 510 // coalescing. The idea would be to initialize the Unhandled list with the | 511 // coalescing. The idea would be to initialize the Unhandled list with the |
| 511 // set of Variables that have no register and a non-empty live range, and | 512 // set of Variables that have no register and a non-empty live range, and |
| 512 // model an infinite number of registers. Maybe use the register aliasing | 513 // model an infinite number of registers. Maybe use the register aliasing |
| 513 // mechanism to get better packing of narrower slots. | 514 // mechanism to get better packing of narrower slots. |
| 515 if (getFlags().getSplitGlobalVars()) | |
| 516 postRegallocSplitting(RegMask); | |
| 517 } | |
| 518 | |
| 519 namespace { | |
| 520 CfgVector<Inst *> getInstructionsInRange(CfgNode *Node, InstNumberT Start, | |
| 521 InstNumberT End) { | |
| 522 CfgVector<Inst *> Result; | |
| 523 bool Started = false; | |
| 524 auto Process = [&](InstList &Insts) { | |
| 525 for (auto &Instr : Insts) { | |
| 526 if (Instr.isDeleted()) { | |
| 527 continue; | |
| 528 } | |
| 529 if (Instr.getNumber() == Start) { | |
| 530 Started = true; | |
| 531 } | |
| 532 if (Started) { | |
| 533 Result.push_back(&Instr); | |
|
Jim Stichnoth
2016/08/02 05:57:50
emplace_back ?
manasijm
2016/08/02 21:41:59
Done.
| |
| 534 } | |
| 535 if (Instr.getNumber() == End) { | |
|
Jim Stichnoth
2016/08/02 05:57:50
Can this be ">=", just to be safe? just in case t
manasijm
2016/08/02 21:41:59
That seems to result in missing a lot of opportuni
| |
| 536 break; | |
| 537 } | |
| 538 } | |
| 539 }; | |
| 540 Process(Node->getPhis()); | |
| 541 Process(Node->getInsts()); | |
| 542 return Result; | |
| 543 } | |
| 544 } | |
|
Jim Stichnoth
2016/08/02 05:57:50
add blank line afterwards
manasijm
2016/08/02 21:41:59
Done.
| |
| 545 void TargetLowering::postRegallocSplitting(const SmallBitVector &RegMask) { | |
| 546 // Splits the live ranges of global(/multi block) variables and runs the | |
| 547 // register allocator to find registers for as many of the new variables as | |
| 548 // possible. | |
| 549 // TODO(manasijm): Merge the small liveranges back into multi-block ones when | |
| 550 // the variables get the same register. This will reduce the amount of new | |
| 551 // instructions inserted. This might involve a full dataflow analysis. | |
| 552 // Also, modify the preference mechanism in the register allocator to match. | |
| 553 | |
| 554 TimerMarker _(TimerStack::TT_splitGlobalVars, Func); | |
| 555 CfgSet<Variable *> SplitCandidates; | |
| 556 | |
| 557 // Find variables that does not have registers but are allowed to. Also skip | |
|
Jim Stichnoth
2016/08/02 05:57:50
that do not
manasijm
2016/08/02 21:41:59
Done.
| |
| 558 // variables with single segment live ranges as they are not split further in | |
| 559 // this function. | |
| 560 for (Variable *Var : Func->getVariables()) { | |
| 561 if (!Var->mustNotHaveReg() && !Var->hasReg()) { | |
| 562 if (Var->getLiveRange().getNumSegments() > 1) | |
| 563 SplitCandidates.insert(Var); | |
| 564 } | |
| 565 } | |
| 566 if (SplitCandidates.empty()) | |
| 567 return; | |
| 568 | |
| 569 CfgSet<Variable *> ExtraVars; | |
| 570 | |
| 571 struct UseInfo { | |
| 572 Variable *Replacing = nullptr; | |
| 573 Inst *FirstUse = nullptr; | |
| 574 Inst *LastDef = nullptr; | |
| 575 SizeT UseCount = 0; | |
| 576 }; | |
| 577 CfgUnorderedMap<Variable *, UseInfo> VarInfo; | |
| 578 // Split the live ranges of the viable variables by node. | |
| 579 // Compute metadata (UseInfo) for each of the resulting variables. | |
| 580 for (auto *Var : SplitCandidates) { | |
| 581 for (auto &Segment : Var->getLiveRange().getSegments()) { | |
| 582 UseInfo Info; | |
| 583 Info.Replacing = Var; | |
| 584 auto *Node = Var->getLiveRange().getNodeForSegment(Segment.first); | |
| 585 | |
| 586 for (auto *Instr : | |
| 587 getInstructionsInRange(Node, Segment.first, Segment.second)) { | |
| 588 for (SizeT i = 0; i < Instr->getSrcSize(); ++i) { | |
| 589 for (SizeT j = 0; j < Instr->getSrc(i)->getNumVars(); ++j) { | |
|
Jim Stichnoth
2016/08/02 05:57:50
For local variable splitting, I made the assumptio
manasijm
2016/08/02 21:41:59
Done.
| |
| 590 auto *Var = Instr->getSrc(i)->getVar(j); | |
| 591 if (Var == Info.Replacing) { | |
| 592 if (Info.FirstUse == nullptr && !llvm::isa<InstPhi>(Instr)) { | |
| 593 Info.FirstUse = Instr; | |
| 594 } | |
| 595 Info.UseCount++; | |
| 596 } | |
| 597 } | |
| 598 } | |
| 599 if (Instr->getDest() == Info.Replacing && !llvm::isa<InstPhi>(Instr)) { | |
|
Jim Stichnoth
2016/08/02 05:57:50
It looks like Phi instructions are not considered
manasijm
2016/08/02 21:41:59
Done.
Jim Stichnoth
2016/08/04 01:59:17
I don't see any new comment or TODO on this issue?
| |
| 600 Info.LastDef = Instr; | |
| 601 } | |
| 602 } | |
| 603 | |
| 604 static constexpr SizeT MinUseThreshold = 3; | |
| 605 // Skip if variable has less than `MinUseThreshold` uses in the segment. | |
| 606 if (Info.UseCount < MinUseThreshold) | |
| 607 continue; | |
| 608 | |
| 609 if (!Info.FirstUse && !Info.LastDef) { | |
| 610 continue; | |
| 611 } | |
| 612 | |
| 613 LiveRange LR; | |
| 614 LR.addSegment(Segment); | |
| 615 Variable *NewVar = Func->makeVariable(Var->getType()); | |
| 616 | |
| 617 NewVar->setLiveRange(LR); | |
| 618 | |
| 619 VarInfo[NewVar] = Info; | |
| 620 | |
| 621 ExtraVars.insert(NewVar); | |
| 622 } | |
| 623 } | |
| 624 // Run the register allocator with all these new variables included | |
| 625 LinearScan RegAlloc(Func); | |
| 626 RegAlloc.init(RAK_Global, SplitCandidates); | |
| 627 RegAlloc.scan(RegMask, getFlags().getRandomizeRegisterAllocation()); | |
| 628 | |
| 629 // Modify the Cfg to use the new variables that now now have registers. | |
|
Jim Stichnoth
2016/08/02 05:57:50
now now
manasijm
2016/08/02 21:41:59
Done.
| |
| 630 for (auto *ExtraVar : ExtraVars) { | |
| 631 if (!ExtraVar->hasReg()) { | |
| 632 continue; | |
| 633 } | |
| 634 | |
| 635 auto &Info = VarInfo[ExtraVar]; | |
| 636 | |
| 637 assert(ExtraVar->getLiveRange().getSegments().size() == 1); | |
| 638 auto Segment = ExtraVar->getLiveRange().getSegments()[0]; | |
| 639 | |
| 640 auto *Node = | |
| 641 Info.Replacing->getLiveRange().getNodeForSegment(Segment.first); | |
| 642 | |
| 643 auto RelevantInsts = | |
| 644 getInstructionsInRange(Node, Segment.first, Segment.second); | |
| 645 | |
| 646 if (RelevantInsts.empty()) | |
| 647 continue; | |
| 648 | |
| 649 // Replace old variables | |
| 650 for (auto *Instr : RelevantInsts) { | |
| 651 if (llvm::isa<InstPhi>(Instr)) | |
| 652 continue; | |
| 653 for (SizeT i = 0; i < Instr->getSrcSize(); ++i) { | |
| 654 // It's safe to iterate over the top-level src operands rather than | |
| 655 // using | |
| 656 // FOREACH_VAR_IN_INST(), because any variables inside e.g. mem operands | |
| 657 // should already have registers. | |
| 658 if (auto *Var = llvm::dyn_cast<Variable>(Instr->getSrc(i))) { | |
| 659 if (Var == Info.Replacing) { | |
| 660 Instr->replaceSource(i, ExtraVar); | |
| 661 } | |
| 662 } | |
| 663 } | |
| 664 if (Instr->getDest() == Info.Replacing) { | |
| 665 Instr->replaceDest(ExtraVar); | |
| 666 } | |
| 667 } | |
| 668 | |
| 669 assert(Info.FirstUse != Info.LastDef); | |
| 670 assert(Info.FirstUse || Info.LastDef); | |
| 671 | |
| 672 // Insert spill code | |
| 673 if (Info.FirstUse != nullptr) { | |
| 674 auto *NewInst = | |
| 675 Func->getTarget()->createLoweredMove(ExtraVar, Info.Replacing); | |
| 676 Node->getInsts().insert(instToIterator(Info.FirstUse), NewInst); | |
| 677 } | |
| 678 if (Info.LastDef != nullptr) { | |
| 679 auto *NewInst = | |
| 680 Func->getTarget()->createLoweredMove(Info.Replacing, ExtraVar); | |
| 681 Node->getInsts().insertAfter(instToIterator(Info.LastDef), NewInst); | |
| 682 } | |
| 683 } | |
| 514 } | 684 } |
| 515 | 685 |
| 516 void TargetLowering::markRedefinitions() { | 686 void TargetLowering::markRedefinitions() { |
| 517 // Find (non-SSA) instructions where the Dest variable appears in some source | 687 // Find (non-SSA) instructions where the Dest variable appears in some source |
| 518 // operand, and set the IsDestRedefined flag to keep liveness analysis | 688 // operand, and set the IsDestRedefined flag to keep liveness analysis |
| 519 // consistent. | 689 // consistent. |
| 520 for (auto Instr = Context.getCur(), E = Context.getNext(); Instr != E; | 690 for (auto Instr = Context.getCur(), E = Context.getNext(); Instr != E; |
| 521 ++Instr) { | 691 ++Instr) { |
| 522 if (Instr->isDeleted()) | 692 if (Instr->isDeleted()) |
| 523 continue; | 693 continue; |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 938 case TARGET_LOWERING_CLASS_FOR(X): \ | 1108 case TARGET_LOWERING_CLASS_FOR(X): \ |
| 939 return ::X::createTargetHeaderLowering(Ctx); | 1109 return ::X::createTargetHeaderLowering(Ctx); |
| 940 #include "SZTargets.def" | 1110 #include "SZTargets.def" |
| 941 #undef SUBZERO_TARGET | 1111 #undef SUBZERO_TARGET |
| 942 } | 1112 } |
| 943 } | 1113 } |
| 944 | 1114 |
| 945 TargetHeaderLowering::~TargetHeaderLowering() = default; | 1115 TargetHeaderLowering::~TargetHeaderLowering() = default; |
| 946 | 1116 |
| 947 } // end of namespace Ice | 1117 } // end of namespace Ice |
| OLD | NEW |