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 |
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 Dest = Source; | 558 Dest = Source; |
559 // Instead of std::sort, we could do a bucket sort with log2(alignment) as | 559 // Instead of std::sort, we could do a bucket sort with log2(alignment) as |
560 // the buckets, if performance is an issue. | 560 // the buckets, if performance is an issue. |
561 std::sort(Dest.begin(), Dest.end(), | 561 std::sort(Dest.begin(), Dest.end(), |
562 [this](const Variable *V1, const Variable *V2) { | 562 [this](const Variable *V1, const Variable *V2) { |
563 return typeWidthInBytesOnStack(V1->getType()) > | 563 return typeWidthInBytesOnStack(V1->getType()) > |
564 typeWidthInBytesOnStack(V2->getType()); | 564 typeWidthInBytesOnStack(V2->getType()); |
565 }); | 565 }); |
566 } | 566 } |
567 | 567 |
568 namespace { | |
569 bool mightHaveStackSlot(const Variable *Var, const BitVector &IsVarReferenced) { | |
570 if (!IsVarReferenced[Var->getIndex()]) | |
571 return false; | |
572 if (Var->hasReg()) | |
573 return false; | |
574 return true; | |
575 } | |
576 } // end of anonymous namespace | |
577 | |
578 void TargetLowering::getVarStackSlotParams( | 568 void TargetLowering::getVarStackSlotParams( |
579 VarList &SortedSpilledVariables, SmallBitVector &RegsUsed, | 569 VarList &SortedSpilledVariables, SmallBitVector &RegsUsed, |
580 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, | 570 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, |
581 uint32_t *SpillAreaAlignmentBytes, uint32_t *LocalsSlotsAlignmentBytes, | 571 uint32_t *SpillAreaAlignmentBytes, uint32_t *LocalsSlotsAlignmentBytes, |
582 std::function<bool(Variable *)> TargetVarHook) { | 572 std::function<bool(Variable *)> TargetVarHook) { |
583 const VariablesMetadata *VMetadata = Func->getVMetadata(); | 573 const VariablesMetadata *VMetadata = Func->getVMetadata(); |
584 BitVector IsVarReferenced(Func->getNumVariables()); | 574 BitVector IsVarReferenced(Func->getNumVariables()); |
585 for (CfgNode *Node : Func->getNodes()) { | 575 for (CfgNode *Node : Func->getNodes()) { |
586 for (Inst &Instr : Node->getInsts()) { | 576 for (Inst &Instr : Node->getInsts()) { |
587 if (Instr.isDeleted()) | 577 if (Instr.isDeleted()) |
588 continue; | 578 continue; |
589 if (const Variable *Var = Instr.getDest()) | 579 if (const Variable *Var = Instr.getDest()) |
590 IsVarReferenced[Var->getIndex()] = true; | 580 IsVarReferenced[Var->getIndex()] = true; |
591 FOREACH_VAR_IN_INST(Var, Instr) { | 581 FOREACH_VAR_IN_INST(Var, Instr) { |
592 IsVarReferenced[Var->getIndex()] = true; | 582 IsVarReferenced[Var->getIndex()] = true; |
593 } | 583 } |
594 } | 584 } |
595 } | 585 } |
596 | 586 |
597 // Find each variable Var where: | |
598 // - Var is actively referenced | |
599 // - Var does not have a register | |
600 // - Var's furthest ancestor through LinkedTo: Root | |
601 // - Root has no active references, or has a register | |
602 // | |
603 // When any such Var is found, rotate the LinkedTo tree by swapping | |
604 // Var->LinkedTo and Root->LinkedTo. This ensures that when Var needs a stack | |
605 // slot, either its LinkedTo field is nullptr, or Var->getLinkedToRoot() | |
606 // returns a variable with a stack slot. | |
607 for (Variable *Var : Func->getVariables()) { | |
608 if (!mightHaveStackSlot(Var, IsVarReferenced)) | |
609 continue; | |
610 if (Variable *Root = Var->getLinkedToRoot()) { | |
611 assert(Root->getLinkedTo() == nullptr); | |
612 if (mightHaveStackSlot(Root, IsVarReferenced)) { | |
613 // Found a "safe" root, no need to rotate the tree. | |
614 continue; | |
615 } | |
616 Var->setLinkedTo(nullptr); | |
617 Root->setLinkedTo(Var); | |
618 } | |
619 } | |
620 | |
621 // If SimpleCoalescing is false, each variable without a register gets its | 587 // If SimpleCoalescing is false, each variable without a register gets its |
622 // own unique stack slot, which leads to large stack frames. If | 588 // own unique stack slot, which leads to large stack frames. If |
623 // SimpleCoalescing is true, then each "global" variable without a register | 589 // SimpleCoalescing is true, then each "global" variable without a register |
624 // gets its own slot, but "local" variable slots are reused across basic | 590 // gets its own slot, but "local" variable slots are reused across basic |
625 // blocks. E.g., if A and B are local to block 1 and C is local to block 2, | 591 // blocks. E.g., if A and B are local to block 1 and C is local to block 2, |
626 // then C may share a slot with A or B. | 592 // then C may share a slot with A or B. |
627 // | 593 // |
628 // We cannot coalesce stack slots if this function calls a "returns twice" | 594 // We cannot coalesce stack slots if this function calls a "returns twice" |
629 // function. In that case, basic blocks may be revisited, and variables local | 595 // function. In that case, basic blocks may be revisited, and variables local |
630 // to those basic blocks are actually live until after the called function | 596 // to those basic blocks are actually live until after the called function |
631 // returns a second time. | 597 // returns a second time. |
632 const bool SimpleCoalescing = !callsReturnsTwice(); | 598 const bool SimpleCoalescing = !callsReturnsTwice(); |
633 | 599 |
634 CfgVector<size_t> LocalsSize(Func->getNumNodes()); | 600 CfgVector<size_t> LocalsSize(Func->getNumNodes()); |
635 const VarList &Variables = Func->getVariables(); | 601 const VarList &Variables = Func->getVariables(); |
636 VarList SpilledVariables; | 602 VarList SpilledVariables; |
637 for (Variable *Var : Variables) { | 603 for (Variable *Var : Variables) { |
638 if (Var->hasReg()) { | 604 if (Var->hasReg()) { |
639 // Don't consider a rematerializable variable to be an actual register use | 605 // Don't consider a rematerializable variable to be an actual register use |
640 // (specifically of the frame pointer). Otherwise, the prolog may decide | 606 // (specifically of the frame pointer). Otherwise, the prolog may decide |
641 // to save the frame pointer twice - once because of the explicit need for | 607 // to save the frame pointer twice - once because of the explicit need for |
642 // a frame pointer, and once because of an active use of a callee-save | 608 // a frame pointer, and once because of an active use of a callee-save |
643 // register. | 609 // register. |
644 if (!Var->isRematerializable()) | 610 if (!Var->isRematerializable()) |
645 RegsUsed[Var->getRegNum()] = true; | 611 RegsUsed[Var->getRegNum()] = true; |
646 continue; | 612 continue; |
647 } | 613 } |
648 // An argument either does not need a stack slot (if passed in a register) | 614 // An argument either does not need a stack slot (if passed in a register) |
649 // or already has one (if passed on the stack). | 615 // or already has one (if passed on the stack). |
650 if (Var->getIsArg()) | 616 if (Var->getIsArg()) { |
| 617 if (!Var->hasReg()) { |
| 618 assert(!Var->hasStackOffset()); |
| 619 Var->setHasStackOffset(); |
| 620 } |
651 continue; | 621 continue; |
| 622 } |
652 // An unreferenced variable doesn't need a stack slot. | 623 // An unreferenced variable doesn't need a stack slot. |
653 if (!IsVarReferenced[Var->getIndex()]) | 624 if (!IsVarReferenced[Var->getIndex()]) |
654 continue; | 625 continue; |
655 // Check a target-specific variable (it may end up sharing stack slots) and | 626 // Check a target-specific variable (it may end up sharing stack slots) and |
656 // not need accounting here. | 627 // not need accounting here. |
657 if (TargetVarHook(Var)) | 628 if (TargetVarHook(Var)) |
658 continue; | 629 continue; |
| 630 assert(!Var->hasStackOffset()); |
| 631 Var->setHasStackOffset(); |
659 SpilledVariables.push_back(Var); | 632 SpilledVariables.push_back(Var); |
660 } | 633 } |
661 | 634 |
662 SortedSpilledVariables.reserve(SpilledVariables.size()); | 635 SortedSpilledVariables.reserve(SpilledVariables.size()); |
663 sortVarsByAlignment(SortedSpilledVariables, SpilledVariables); | 636 sortVarsByAlignment(SortedSpilledVariables, SpilledVariables); |
664 | 637 |
665 for (Variable *Var : SortedSpilledVariables) { | 638 for (Variable *Var : SortedSpilledVariables) { |
666 size_t Increment = typeWidthInBytesOnStack(Var->getType()); | 639 size_t Increment = typeWidthInBytesOnStack(Var->getType()); |
667 // We have sorted by alignment, so the first variable we encounter that is | 640 // We have sorted by alignment, so the first variable we encounter that is |
668 // located in each area determines the max alignment for the area. | 641 // located in each area determines the max alignment for the area. |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 case TARGET_LOWERING_CLASS_FOR(X): \ | 911 case TARGET_LOWERING_CLASS_FOR(X): \ |
939 return ::X::createTargetHeaderLowering(Ctx); | 912 return ::X::createTargetHeaderLowering(Ctx); |
940 #include "SZTargets.def" | 913 #include "SZTargets.def" |
941 #undef SUBZERO_TARGET | 914 #undef SUBZERO_TARGET |
942 } | 915 } |
943 } | 916 } |
944 | 917 |
945 TargetHeaderLowering::~TargetHeaderLowering() = default; | 918 TargetHeaderLowering::~TargetHeaderLowering() = default; |
946 | 919 |
947 } // end of namespace Ice | 920 } // end of namespace Ice |
OLD | NEW |