| OLD | NEW |
| 1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===// | 1 //===- subzero/src/IceCfg.cpp - Control flow graph 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 14 matching lines...) Expand all Loading... |
| 25 #include "IceInstVarIter.h" | 25 #include "IceInstVarIter.h" |
| 26 #include "IceLiveness.h" | 26 #include "IceLiveness.h" |
| 27 #include "IceLoopAnalyzer.h" | 27 #include "IceLoopAnalyzer.h" |
| 28 #include "IceOperand.h" | 28 #include "IceOperand.h" |
| 29 #include "IceTargetLowering.h" | 29 #include "IceTargetLowering.h" |
| 30 | 30 |
| 31 namespace Ice { | 31 namespace Ice { |
| 32 | 32 |
| 33 Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber) | 33 Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber) |
| 34 : Ctx(Ctx), SequenceNumber(SequenceNumber), | 34 : Ctx(Ctx), SequenceNumber(SequenceNumber), |
| 35 VMask(Ctx->getFlags().getVerbose()), NextInstNumber(Inst::NumberInitial), | 35 VMask(Ctx->getFlags().getVerbose()), FunctionName(), |
| 36 Live(nullptr) { | 36 NextInstNumber(Inst::NumberInitial), Live(nullptr) { |
| 37 Allocator.reset(new ArenaAllocator()); | 37 Allocator.reset(new ArenaAllocator()); |
| 38 NodeStrings.reset(new StringPool); |
| 39 VarStrings.reset(new StringPool); |
| 38 CfgLocalAllocatorScope _(this); | 40 CfgLocalAllocatorScope _(this); |
| 39 Target = | 41 Target = |
| 40 TargetLowering::createLowering(Ctx->getFlags().getTargetArch(), this); | 42 TargetLowering::createLowering(Ctx->getFlags().getTargetArch(), this); |
| 41 VMetadata.reset(new VariablesMetadata(this)); | 43 VMetadata.reset(new VariablesMetadata(this)); |
| 42 TargetAssembler = Target->createAssembler(); | 44 TargetAssembler = Target->createAssembler(); |
| 43 | 45 |
| 44 if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Randomize) { | 46 if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Randomize) { |
| 45 // If -randomize-pool-immediates=randomize, create a random number | 47 // If -randomize-pool-immediates=randomize, create a random number |
| 46 // generator to generate a cookie for constant blinding. | 48 // generator to generate a cookie for constant blinding. |
| 47 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), | 49 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), |
| 48 RPE_ConstantBlinding, this->SequenceNumber); | 50 RPE_ConstantBlinding, this->SequenceNumber); |
| 49 ConstantBlindingCookie = | 51 ConstantBlindingCookie = |
| 50 (uint32_t)RNG.next((uint64_t)std::numeric_limits<uint32_t>::max() + 1); | 52 (uint32_t)RNG.next((uint64_t)std::numeric_limits<uint32_t>::max() + 1); |
| 51 } | 53 } |
| 52 } | 54 } |
| 53 | 55 |
| 54 Cfg::~Cfg() { assert(CfgAllocatorTraits::current() == nullptr); } | 56 Cfg::~Cfg() { |
| 57 assert(CfgAllocatorTraits::current() == nullptr); |
| 58 if (GlobalContext::getFlags().getDumpStrings()) { |
| 59 OstreamLocker _(Ctx); |
| 60 Ostream &Str = Ctx->getStrDump(); |
| 61 getNodeStrings()->dump(Str); |
| 62 getVarStrings()->dump(Str); |
| 63 } |
| 64 } |
| 55 | 65 |
| 56 /// Create a string like "foo(i=123:b=9)" indicating the function name, number | 66 /// Create a string like "foo(i=123:b=9)" indicating the function name, number |
| 57 /// of high-level instructions, and number of basic blocks. This string is only | 67 /// of high-level instructions, and number of basic blocks. This string is only |
| 58 /// used for dumping and other diagnostics, and the idea is that given a set of | 68 /// used for dumping and other diagnostics, and the idea is that given a set of |
| 59 /// functions to debug a problem on, it's easy to find the smallest or simplest | 69 /// functions to debug a problem on, it's easy to find the smallest or simplest |
| 60 /// function to attack. Note that the counts may change somewhat depending on | 70 /// function to attack. Note that the counts may change somewhat depending on |
| 61 /// what point it is called during the translation passes. | 71 /// what point it is called during the translation passes. |
| 62 IceString Cfg::getFunctionNameAndSize() const { | 72 std::string Cfg::getFunctionNameAndSize() const { |
| 63 if (!BuildDefs::dump()) | 73 if (!BuildDefs::dump()) |
| 64 return getFunctionName(); | 74 return getFunctionName().toString(); |
| 65 SizeT NodeCount = 0; | 75 SizeT NodeCount = 0; |
| 66 SizeT InstCount = 0; | 76 SizeT InstCount = 0; |
| 67 for (CfgNode *Node : getNodes()) { | 77 for (CfgNode *Node : getNodes()) { |
| 68 ++NodeCount; | 78 ++NodeCount; |
| 69 // Note: deleted instructions are *not* ignored. | 79 // Note: deleted instructions are *not* ignored. |
| 70 InstCount += Node->getPhis().size(); | 80 InstCount += Node->getPhis().size(); |
| 71 for (Inst &I : Node->getInsts()) { | 81 for (Inst &I : Node->getInsts()) { |
| 72 if (!llvm::isa<InstTarget>(&I)) | 82 if (!llvm::isa<InstTarget>(&I)) |
| 73 ++InstCount; | 83 ++InstCount; |
| 74 } | 84 } |
| 75 } | 85 } |
| 76 return getFunctionName() + "(i=" + std::to_string(InstCount) + ":b=" + | 86 return getFunctionName() + "(i=" + std::to_string(InstCount) + ":b=" + |
| 77 std::to_string(NodeCount) + ")"; | 87 std::to_string(NodeCount) + ")"; |
| 78 } | 88 } |
| 79 | 89 |
| 80 void Cfg::setError(const IceString &Message) { | 90 void Cfg::setError(const std::string &Message) { |
| 81 HasError = true; | 91 HasError = true; |
| 82 ErrorMessage = Message; | 92 ErrorMessage = Message; |
| 83 } | 93 } |
| 84 | 94 |
| 85 CfgNode *Cfg::makeNode() { | 95 CfgNode *Cfg::makeNode() { |
| 86 SizeT LabelIndex = Nodes.size(); | 96 SizeT LabelIndex = Nodes.size(); |
| 87 auto *Node = CfgNode::create(this, LabelIndex); | 97 auto *Node = CfgNode::create(this, LabelIndex); |
| 88 Nodes.push_back(Node); | 98 Nodes.push_back(Node); |
| 89 return Node; | 99 return Node; |
| 90 } | 100 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 117 | 127 |
| 118 // Returns whether the stack frame layout has been computed yet. This is used | 128 // Returns whether the stack frame layout has been computed yet. This is used |
| 119 // for dumping the stack frame location of Variables. | 129 // for dumping the stack frame location of Variables. |
| 120 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } | 130 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } |
| 121 | 131 |
| 122 namespace { | 132 namespace { |
| 123 constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$"; | 133 constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$"; |
| 124 constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$"; | 134 constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$"; |
| 125 } // end of anonymous namespace | 135 } // end of anonymous namespace |
| 126 | 136 |
| 127 void Cfg::createNodeNameDeclaration(const IceString &NodeAsmName) { | 137 void Cfg::createNodeNameDeclaration(const std::string &NodeAsmName) { |
| 128 auto *Var = VariableDeclaration::create(GlobalInits.get()); | 138 auto *Var = VariableDeclaration::create(GlobalInits.get()); |
| 129 Var->setName(BlockNameGlobalPrefix + NodeAsmName); | 139 Var->setName(Ctx, BlockNameGlobalPrefix + NodeAsmName); |
| 130 Var->setIsConstant(true); | 140 Var->setIsConstant(true); |
| 131 Var->addInitializer(VariableDeclaration::DataInitializer::create( | 141 Var->addInitializer(VariableDeclaration::DataInitializer::create( |
| 132 GlobalInits.get(), NodeAsmName.data(), NodeAsmName.size() + 1)); | 142 GlobalInits.get(), NodeAsmName.data(), NodeAsmName.size() + 1)); |
| 133 const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); | 143 const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); |
| 134 Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes. | 144 Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes. |
| 135 GlobalInits->push_back(Var); | 145 GlobalInits->push_back(Var); |
| 136 } | 146 } |
| 137 | 147 |
| 138 void Cfg::createBlockProfilingInfoDeclaration( | 148 void Cfg::createBlockProfilingInfoDeclaration( |
| 139 const IceString &NodeAsmName, VariableDeclaration *NodeNameDeclaration) { | 149 const std::string &NodeAsmName, VariableDeclaration *NodeNameDeclaration) { |
| 140 auto *Var = VariableDeclaration::create(GlobalInits.get()); | 150 auto *Var = VariableDeclaration::create(GlobalInits.get()); |
| 141 Var->setName(BlockStatsGlobalPrefix + NodeAsmName); | 151 Var->setName(Ctx, BlockStatsGlobalPrefix + NodeAsmName); |
| 142 const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); | 152 const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); |
| 143 Var->addInitializer(VariableDeclaration::ZeroInitializer::create( | 153 Var->addInitializer(VariableDeclaration::ZeroInitializer::create( |
| 144 GlobalInits.get(), Int64ByteSize)); | 154 GlobalInits.get(), Int64ByteSize)); |
| 145 | 155 |
| 146 const RelocOffsetT NodeNameDeclarationOffset = 0; | 156 const RelocOffsetT NodeNameDeclarationOffset = 0; |
| 147 Var->addInitializer(VariableDeclaration::RelocInitializer::create( | 157 Var->addInitializer(VariableDeclaration::RelocInitializer::create( |
| 148 GlobalInits.get(), NodeNameDeclaration, | 158 GlobalInits.get(), NodeNameDeclaration, |
| 149 {RelocOffset::create(Ctx, NodeNameDeclarationOffset)})); | 159 {RelocOffset::create(Ctx, NodeNameDeclarationOffset)})); |
| 150 Var->setAlignment(Int64ByteSize); | 160 Var->setAlignment(Int64ByteSize); |
| 151 GlobalInits->push_back(Var); | 161 GlobalInits->push_back(Var); |
| 152 } | 162 } |
| 153 | 163 |
| 154 void Cfg::profileBlocks() { | 164 void Cfg::profileBlocks() { |
| 155 if (GlobalInits == nullptr) | 165 if (GlobalInits == nullptr) |
| 156 GlobalInits.reset(new VariableDeclarationList()); | 166 GlobalInits.reset(new VariableDeclarationList()); |
| 157 | 167 |
| 158 for (CfgNode *Node : Nodes) { | 168 for (CfgNode *Node : Nodes) { |
| 159 const IceString NodeAsmName = Node->getAsmName(); | 169 const std::string NodeAsmName = Node->getAsmName(); |
| 160 createNodeNameDeclaration(NodeAsmName); | 170 createNodeNameDeclaration(NodeAsmName); |
| 161 createBlockProfilingInfoDeclaration(NodeAsmName, GlobalInits->back()); | 171 createBlockProfilingInfoDeclaration(NodeAsmName, GlobalInits->back()); |
| 162 Node->profileExecutionCount(GlobalInits->back()); | 172 Node->profileExecutionCount(GlobalInits->back()); |
| 163 } | 173 } |
| 164 } | 174 } |
| 165 | 175 |
| 166 bool Cfg::isProfileGlobal(const VariableDeclaration &Var) { | 176 bool Cfg::isProfileGlobal(const VariableDeclaration &Var) { |
| 167 return Var.getName().find(BlockStatsGlobalPrefix) == 0; | 177 if (!Var.getName().hasStdString()) |
| 178 return false; |
| 179 return Var.getName().toString().find(BlockStatsGlobalPrefix) == 0; |
| 168 } | 180 } |
| 169 | 181 |
| 170 void Cfg::addCallToProfileSummary() { | 182 void Cfg::addCallToProfileSummary() { |
| 171 // The call(s) to __Sz_profile_summary are added by the profiler in functions | 183 // The call(s) to __Sz_profile_summary are added by the profiler in functions |
| 172 // that cause the program to exit. This function is defined in | 184 // that cause the program to exit. This function is defined in |
| 173 // runtime/szrt_profiler.c. | 185 // runtime/szrt_profiler.c. |
| 174 Constant *ProfileSummarySym = | 186 Constant *ProfileSummarySym = |
| 175 Ctx->getConstantExternSym("__Sz_profile_summary"); | 187 Ctx->getConstantExternSym(Ctx->getGlobalString("__Sz_profile_summary")); |
| 176 constexpr SizeT NumArgs = 0; | 188 constexpr SizeT NumArgs = 0; |
| 177 constexpr Variable *Void = nullptr; | 189 constexpr Variable *Void = nullptr; |
| 178 constexpr bool HasTailCall = false; | 190 constexpr bool HasTailCall = false; |
| 179 auto *Call = | 191 auto *Call = |
| 180 InstCall::create(this, NumArgs, Void, ProfileSummarySym, HasTailCall); | 192 InstCall::create(this, NumArgs, Void, ProfileSummarySym, HasTailCall); |
| 181 getEntryNode()->getInsts().push_front(Call); | 193 getEntryNode()->getInsts().push_front(Call); |
| 182 } | 194 } |
| 183 | 195 |
| 184 void Cfg::translate() { | 196 void Cfg::translate() { |
| 185 if (hasError()) | 197 if (hasError()) |
| 186 return; | 198 return; |
| 187 if (BuildDefs::dump()) { | 199 if (BuildDefs::dump()) { |
| 188 const IceString &TimingFocusOn = | 200 const std::string TimingFocusOn = |
| 189 getContext()->getFlags().getTimingFocusOn(); | 201 getContext()->getFlags().getTimingFocusOn(); |
| 190 const IceString &Name = getFunctionName(); | 202 const std::string Name = getFunctionName().toString(); |
| 191 if (TimingFocusOn == "*" || TimingFocusOn == Name) { | 203 if (TimingFocusOn == "*" || TimingFocusOn == Name) { |
| 192 setFocusedTiming(); | 204 setFocusedTiming(); |
| 193 getContext()->resetTimer(GlobalContext::TSK_Default); | 205 getContext()->resetTimer(GlobalContext::TSK_Default); |
| 194 getContext()->setTimerName(GlobalContext::TSK_Default, Name); | 206 getContext()->setTimerName(GlobalContext::TSK_Default, Name); |
| 195 } | 207 } |
| 196 if (isVerbose(IceV_Status)) { | 208 if (isVerbose(IceV_Status)) { |
| 197 getContext()->getStrDump() << ">>>Translating " | 209 getContext()->getStrDump() << ">>>Translating " |
| 198 << getFunctionNameAndSize() << "\n"; | 210 << getFunctionNameAndSize() << "\n"; |
| 199 } | 211 } |
| 200 } | 212 } |
| 201 TimerMarker T_func(getContext(), getFunctionName()); | 213 TimerMarker T_func(getContext(), getFunctionName().toStringOrEmpty()); |
| 202 TimerMarker T(TimerStack::TT_translate, this); | 214 TimerMarker T(TimerStack::TT_translate, this); |
| 203 | 215 |
| 204 dump("Initial CFG"); | 216 dump("Initial CFG"); |
| 205 | 217 |
| 206 if (getContext()->getFlags().getEnableBlockProfile()) { | 218 if (getContext()->getFlags().getEnableBlockProfile()) { |
| 207 profileBlocks(); | 219 profileBlocks(); |
| 208 // TODO(jpp): this is fragile, at best. Figure out a better way of | 220 // TODO(jpp): this is fragile, at best. Figure out a better way of |
| 209 // detecting exit functions. | 221 // detecting exit functions. |
| 210 if (GlobalContext::matchSymbolName(getFunctionName(), "exit")) { | 222 if (GlobalContext::matchSymbolName(getFunctionName(), "exit")) { |
| 211 addCallToProfileSummary(); | 223 addCallToProfileSummary(); |
| (...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 for (const InstJumpTable *JT : JumpTables) | 971 for (const InstJumpTable *JT : JumpTables) |
| 960 for (SizeT I = 0; I < JT->getNumTargets(); ++I) | 972 for (SizeT I = 0; I < JT->getNumTargets(); ++I) |
| 961 JT->getTarget(I)->setNeedsAlignment(); | 973 JT->getTarget(I)->setNeedsAlignment(); |
| 962 } | 974 } |
| 963 | 975 |
| 964 // ======================== Dump routines ======================== // | 976 // ======================== Dump routines ======================== // |
| 965 | 977 |
| 966 // emitTextHeader() is not target-specific (apart from what is abstracted by | 978 // emitTextHeader() is not target-specific (apart from what is abstracted by |
| 967 // the Assembler), so it is defined here rather than in the target lowering | 979 // the Assembler), so it is defined here rather than in the target lowering |
| 968 // class. | 980 // class. |
| 969 void Cfg::emitTextHeader(const IceString &Name, GlobalContext *Ctx, | 981 void Cfg::emitTextHeader(GlobalString Name, GlobalContext *Ctx, |
| 970 const Assembler *Asm) { | 982 const Assembler *Asm) { |
| 971 if (!BuildDefs::dump()) | 983 if (!BuildDefs::dump()) |
| 972 return; | 984 return; |
| 973 Ostream &Str = Ctx->getStrEmit(); | 985 Ostream &Str = Ctx->getStrEmit(); |
| 974 Str << "\t.text\n"; | 986 Str << "\t.text\n"; |
| 975 if (Ctx->getFlags().getFunctionSections()) | 987 if (Ctx->getFlags().getFunctionSections()) |
| 976 Str << "\t.section\t.text." << Name << ",\"ax\",%progbits\n"; | 988 Str << "\t.section\t.text." << Name << ",\"ax\",%progbits\n"; |
| 977 if (!Asm->getInternal() || Ctx->getFlags().getDisableInternal()) { | 989 if (!Asm->getInternal() || Ctx->getFlags().getDisableInternal()) { |
| 978 Str << "\t.globl\t" << Name << "\n"; | 990 Str << "\t.globl\t" << Name << "\n"; |
| 979 Str << "\t.type\t" << Name << ",%function\n"; | 991 Str << "\t.type\t" << Name << ",%function\n"; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1135 } | 1147 } |
| 1136 } | 1148 } |
| 1137 // Print each basic block | 1149 // Print each basic block |
| 1138 for (CfgNode *Node : Nodes) | 1150 for (CfgNode *Node : Nodes) |
| 1139 Node->dump(this); | 1151 Node->dump(this); |
| 1140 if (isVerbose(IceV_Instructions)) | 1152 if (isVerbose(IceV_Instructions)) |
| 1141 Str << "}\n"; | 1153 Str << "}\n"; |
| 1142 } | 1154 } |
| 1143 | 1155 |
| 1144 } // end of namespace Ice | 1156 } // end of namespace Ice |
| OLD | NEW |