OLD | NEW |
1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) implementation -----===// | 1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) 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 // This file implements the CfgNode class, including the complexities | 10 // This file implements the CfgNode class, including the complexities |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 // this node, only one edge is split, and the particular choice of | 215 // this node, only one edge is split, and the particular choice of |
216 // edge is undefined. This could happen with a switch instruction, or | 216 // edge is undefined. This could happen with a switch instruction, or |
217 // a conditional branch that weirdly has both branches to the same | 217 // a conditional branch that weirdly has both branches to the same |
218 // place. TODO(stichnot,kschimpf): Figure out whether this is legal | 218 // place. TODO(stichnot,kschimpf): Figure out whether this is legal |
219 // in the LLVM IR or the PNaCl bitcode, and if so, we need to | 219 // in the LLVM IR or the PNaCl bitcode, and if so, we need to |
220 // establish a strong relationship among the ordering of Pred's | 220 // establish a strong relationship among the ordering of Pred's |
221 // out-edge list, this node's in-edge list, and the Phi instruction's | 221 // out-edge list, this node's in-edge list, and the Phi instruction's |
222 // operand list. | 222 // operand list. |
223 CfgNode *CfgNode::splitIncomingEdge(CfgNode *Pred, SizeT EdgeIndex) { | 223 CfgNode *CfgNode::splitIncomingEdge(CfgNode *Pred, SizeT EdgeIndex) { |
224 CfgNode *NewNode = Func->makeNode(); | 224 CfgNode *NewNode = Func->makeNode(); |
225 if (ALLOW_DUMP) | 225 if (buildAllowsDump()) |
226 NewNode->setName("split_" + Pred->getName() + "_" + getName() + "_" + | 226 NewNode->setName("split_" + Pred->getName() + "_" + getName() + "_" + |
227 std::to_string(EdgeIndex)); | 227 std::to_string(EdgeIndex)); |
228 // The new node is added to the end of the node list, and will later | 228 // The new node is added to the end of the node list, and will later |
229 // need to be sorted into a reasonable topological order. | 229 // need to be sorted into a reasonable topological order. |
230 NewNode->setNeedsPlacement(true); | 230 NewNode->setNeedsPlacement(true); |
231 // Repoint Pred's out-edge. | 231 // Repoint Pred's out-edge. |
232 bool Found = false; | 232 bool Found = false; |
233 for (auto I = Pred->OutEdges.begin(), E = Pred->OutEdges.end(); | 233 for (auto I = Pred->OutEdges.begin(), E = Pred->OutEdges.end(); |
234 !Found && I != E; ++I) { | 234 !Found && I != E; ++I) { |
235 if (*I == this) { | 235 if (*I == this) { |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 // If the target instruction "A=B" is part of a cycle, find | 430 // If the target instruction "A=B" is part of a cycle, find |
431 // the "X=A" assignment in the cycle because it will have to | 431 // the "X=A" assignment in the cycle because it will have to |
432 // be rewritten as "X=tmp". | 432 // be rewritten as "X=tmp". |
433 for (size_t J = 0; !Found && J < NumPhis; ++J) { | 433 for (size_t J = 0; !Found && J < NumPhis; ++J) { |
434 if (Desc[J].Processed) | 434 if (Desc[J].Processed) |
435 continue; | 435 continue; |
436 Operand *OtherSrc = Desc[J].Src; | 436 Operand *OtherSrc = Desc[J].Src; |
437 if (Desc[J].NumPred && sameVarOrReg(Dest, OtherSrc)) { | 437 if (Desc[J].NumPred && sameVarOrReg(Dest, OtherSrc)) { |
438 SizeT VarNum = Func->getNumVariables(); | 438 SizeT VarNum = Func->getNumVariables(); |
439 Variable *Tmp = Func->makeVariable(OtherSrc->getType()); | 439 Variable *Tmp = Func->makeVariable(OtherSrc->getType()); |
440 if (ALLOW_DUMP) | 440 if (buildAllowsDump()) |
441 Tmp->setName(Func, "__split_" + std::to_string(VarNum)); | 441 Tmp->setName(Func, "__split_" + std::to_string(VarNum)); |
442 Assignments.push_back(InstAssign::create(Func, Tmp, OtherSrc)); | 442 Assignments.push_back(InstAssign::create(Func, Tmp, OtherSrc)); |
443 Desc[J].Src = Tmp; | 443 Desc[J].Src = Tmp; |
444 Found = true; | 444 Found = true; |
445 } | 445 } |
446 } | 446 } |
447 assert(Found); | 447 assert(Found); |
448 } | 448 } |
449 // Now that a cycle (if any) has been broken, create the actual | 449 // Now that a cycle (if any) has been broken, create the actual |
450 // assignment. | 450 // assignment. |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 // set bits for global variables upon block entry. We validate this | 602 // set bits for global variables upon block entry. We validate this |
603 // by shrinking the Live vector and then testing it against the | 603 // by shrinking the Live vector and then testing it against the |
604 // pre-shrunk version. (The shrinking is required, but the | 604 // pre-shrunk version. (The shrinking is required, but the |
605 // validation is not.) | 605 // validation is not.) |
606 LivenessBV LiveOrig = Live; | 606 LivenessBV LiveOrig = Live; |
607 Live.resize(Liveness->getNumGlobalVars()); | 607 Live.resize(Liveness->getNumGlobalVars()); |
608 // Non-global arguments in the entry node are allowed to be live on | 608 // Non-global arguments in the entry node are allowed to be live on |
609 // entry. | 609 // entry. |
610 bool IsEntry = (Func->getEntryNode() == this); | 610 bool IsEntry = (Func->getEntryNode() == this); |
611 if (!(IsEntry || Live == LiveOrig)) { | 611 if (!(IsEntry || Live == LiveOrig)) { |
612 if (ALLOW_DUMP) { | 612 if (buildAllowsDump()) { |
613 // This is a fatal liveness consistency error. Print some | 613 // This is a fatal liveness consistency error. Print some |
614 // diagnostics and abort. | 614 // diagnostics and abort. |
615 Ostream &Str = Func->getContext()->getStrDump(); | 615 Ostream &Str = Func->getContext()->getStrDump(); |
616 Func->resetCurrentNode(); | 616 Func->resetCurrentNode(); |
617 Str << "LiveOrig-Live ="; | 617 Str << "LiveOrig-Live ="; |
618 for (SizeT i = Live.size(); i < LiveOrig.size(); ++i) { | 618 for (SizeT i = Live.size(); i < LiveOrig.size(); ++i) { |
619 if (LiveOrig.test(i)) { | 619 if (LiveOrig.test(i)) { |
620 Str << " "; | 620 Str << " "; |
621 Liveness->getVariable(i, this)->dump(Func); | 621 Liveness->getVariable(i, this)->dump(Func); |
622 } | 622 } |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 } | 775 } |
776 | 776 |
777 // ======================== Dump routines ======================== // | 777 // ======================== Dump routines ======================== // |
778 | 778 |
779 namespace { | 779 namespace { |
780 | 780 |
781 // Helper functions for emit(). | 781 // Helper functions for emit(). |
782 | 782 |
783 void emitRegisterUsage(Ostream &Str, const Cfg *Func, const CfgNode *Node, | 783 void emitRegisterUsage(Ostream &Str, const Cfg *Func, const CfgNode *Node, |
784 bool IsLiveIn, std::vector<SizeT> &LiveRegCount) { | 784 bool IsLiveIn, std::vector<SizeT> &LiveRegCount) { |
785 if (!ALLOW_DUMP) | 785 if (!buildAllowsDump()) |
786 return; | 786 return; |
787 Liveness *Liveness = Func->getLiveness(); | 787 Liveness *Liveness = Func->getLiveness(); |
788 const LivenessBV *Live; | 788 const LivenessBV *Live; |
789 if (IsLiveIn) { | 789 if (IsLiveIn) { |
790 Live = &Liveness->getLiveIn(Node); | 790 Live = &Liveness->getLiveIn(Node); |
791 Str << "\t\t\t\t# LiveIn="; | 791 Str << "\t\t\t\t# LiveIn="; |
792 } else { | 792 } else { |
793 Live = &Liveness->getLiveOut(Node); | 793 Live = &Liveness->getLiveOut(Node); |
794 Str << "\t\t\t\t# LiveOut="; | 794 Str << "\t\t\t\t# LiveOut="; |
795 } | 795 } |
(...skipping 21 matching lines...) Expand all Loading... |
817 Str << ","; | 817 Str << ","; |
818 First = false; | 818 First = false; |
819 Var->emit(Func); | 819 Var->emit(Func); |
820 } | 820 } |
821 } | 821 } |
822 Str << "\n"; | 822 Str << "\n"; |
823 } | 823 } |
824 | 824 |
825 void emitLiveRangesEnded(Ostream &Str, const Cfg *Func, const Inst *Instr, | 825 void emitLiveRangesEnded(Ostream &Str, const Cfg *Func, const Inst *Instr, |
826 std::vector<SizeT> &LiveRegCount) { | 826 std::vector<SizeT> &LiveRegCount) { |
827 if (!ALLOW_DUMP) | 827 if (!buildAllowsDump()) |
828 return; | 828 return; |
829 bool First = true; | 829 bool First = true; |
830 Variable *Dest = Instr->getDest(); | 830 Variable *Dest = Instr->getDest(); |
831 // Normally we increment the live count for the dest register. But | 831 // Normally we increment the live count for the dest register. But |
832 // we shouldn't if the instruction's IsDestNonKillable flag is set, | 832 // we shouldn't if the instruction's IsDestNonKillable flag is set, |
833 // because this means that the target lowering created this | 833 // because this means that the target lowering created this |
834 // instruction as a non-SSA assignment; i.e., a different, previous | 834 // instruction as a non-SSA assignment; i.e., a different, previous |
835 // instruction started the dest variable's live range. | 835 // instruction started the dest variable's live range. |
836 if (!Instr->isDestNonKillable() && Dest && Dest->hasReg()) | 836 if (!Instr->isDestNonKillable() && Dest && Dest->hasReg()) |
837 ++LiveRegCount[Dest->getRegNum()]; | 837 ++LiveRegCount[Dest->getRegNum()]; |
(...skipping 15 matching lines...) Expand all Loading... |
853 else | 853 else |
854 Str << ","; | 854 Str << ","; |
855 Var->emit(Func); | 855 Var->emit(Func); |
856 First = false; | 856 First = false; |
857 } | 857 } |
858 } | 858 } |
859 } | 859 } |
860 } | 860 } |
861 | 861 |
862 void updateStats(Cfg *Func, const Inst *I) { | 862 void updateStats(Cfg *Func, const Inst *I) { |
863 if (!ALLOW_DUMP) | 863 if (!buildAllowsDump()) |
864 return; | 864 return; |
865 // Update emitted instruction count, plus fill/spill count for | 865 // Update emitted instruction count, plus fill/spill count for |
866 // Variable operands without a physical register. | 866 // Variable operands without a physical register. |
867 if (uint32_t Count = I->getEmitInstCount()) { | 867 if (uint32_t Count = I->getEmitInstCount()) { |
868 Func->getContext()->statsUpdateEmitted(Count); | 868 Func->getContext()->statsUpdateEmitted(Count); |
869 if (Variable *Dest = I->getDest()) { | 869 if (Variable *Dest = I->getDest()) { |
870 if (!Dest->hasReg()) | 870 if (!Dest->hasReg()) |
871 Func->getContext()->statsUpdateFills(); | 871 Func->getContext()->statsUpdateFills(); |
872 } | 872 } |
873 for (SizeT S = 0; S < I->getSrcSize(); ++S) { | 873 for (SizeT S = 0; S < I->getSrcSize(); ++S) { |
874 if (Variable *Src = llvm::dyn_cast<Variable>(I->getSrc(S))) { | 874 if (Variable *Src = llvm::dyn_cast<Variable>(I->getSrc(S))) { |
875 if (!Src->hasReg()) | 875 if (!Src->hasReg()) |
876 Func->getContext()->statsUpdateSpills(); | 876 Func->getContext()->statsUpdateSpills(); |
877 } | 877 } |
878 } | 878 } |
879 } | 879 } |
880 } | 880 } |
881 | 881 |
882 } // end of anonymous namespace | 882 } // end of anonymous namespace |
883 | 883 |
884 void CfgNode::emit(Cfg *Func) const { | 884 void CfgNode::emit(Cfg *Func) const { |
885 if (!ALLOW_DUMP) | 885 if (!buildAllowsDump()) |
886 return; | 886 return; |
887 Func->setCurrentNode(this); | 887 Func->setCurrentNode(this); |
888 Ostream &Str = Func->getContext()->getStrEmit(); | 888 Ostream &Str = Func->getContext()->getStrEmit(); |
889 Liveness *Liveness = Func->getLiveness(); | 889 Liveness *Liveness = Func->getLiveness(); |
890 bool DecorateAsm = | 890 bool DecorateAsm = |
891 Liveness && Func->getContext()->getFlags().getDecorateAsm(); | 891 Liveness && Func->getContext()->getFlags().getDecorateAsm(); |
892 Str << getAsmName() << ":\n"; | 892 Str << getAsmName() << ":\n"; |
893 // LiveRegCount keeps track of the number of currently live | 893 // LiveRegCount keeps track of the number of currently live |
894 // variables that each register is assigned to. Normally that would | 894 // variables that each register is assigned to. Normally that would |
895 // be only 0 or 1, but the register allocator's AllowOverlap | 895 // be only 0 or 1, but the register allocator's AllowOverlap |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 } | 1156 } |
1157 } | 1157 } |
1158 | 1158 |
1159 // Don't allow bundle locking across basic blocks, to keep the | 1159 // Don't allow bundle locking across basic blocks, to keep the |
1160 // backtracking mechanism simple. | 1160 // backtracking mechanism simple. |
1161 assert(!Helper.isInBundleLockRegion()); | 1161 assert(!Helper.isInBundleLockRegion()); |
1162 assert(!Retrying); | 1162 assert(!Retrying); |
1163 } | 1163 } |
1164 | 1164 |
1165 void CfgNode::dump(Cfg *Func) const { | 1165 void CfgNode::dump(Cfg *Func) const { |
1166 if (!ALLOW_DUMP) | 1166 if (!buildAllowsDump()) |
1167 return; | 1167 return; |
1168 Func->setCurrentNode(this); | 1168 Func->setCurrentNode(this); |
1169 Ostream &Str = Func->getContext()->getStrDump(); | 1169 Ostream &Str = Func->getContext()->getStrDump(); |
1170 Liveness *Liveness = Func->getLiveness(); | 1170 Liveness *Liveness = Func->getLiveness(); |
1171 if (Func->isVerbose(IceV_Instructions)) { | 1171 if (Func->isVerbose(IceV_Instructions)) { |
1172 Str << getName() << ":\n"; | 1172 Str << getName() << ":\n"; |
1173 } | 1173 } |
1174 // Dump list of predecessor nodes. | 1174 // Dump list of predecessor nodes. |
1175 if (Func->isVerbose(IceV_Preds) && !InEdges.empty()) { | 1175 if (Func->isVerbose(IceV_Preds) && !InEdges.empty()) { |
1176 Str << " // preds = "; | 1176 Str << " // preds = "; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 InstIntrinsicCall *Inst = InstIntrinsicCall::create( | 1266 InstIntrinsicCall *Inst = InstIntrinsicCall::create( |
1267 Func, 5, Func->makeVariable(IceType_i64), RMWI64Name, Info->Info); | 1267 Func, 5, Func->makeVariable(IceType_i64), RMWI64Name, Info->Info); |
1268 Inst->addArg(AtomicRMWOp); | 1268 Inst->addArg(AtomicRMWOp); |
1269 Inst->addArg(Counter); | 1269 Inst->addArg(Counter); |
1270 Inst->addArg(One); | 1270 Inst->addArg(One); |
1271 Inst->addArg(OrderAcquireRelease); | 1271 Inst->addArg(OrderAcquireRelease); |
1272 Insts.push_front(Inst); | 1272 Insts.push_front(Inst); |
1273 } | 1273 } |
1274 | 1274 |
1275 } // end of namespace Ice | 1275 } // end of namespace Ice |
OLD | NEW |