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