Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// | 1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// |
| 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 defines aspects of the compilation that persist across | 10 // This file defines aspects of the compilation that persist across |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 Str << "\n"; | 127 Str << "\n"; |
| 128 } | 128 } |
| 129 | 129 |
| 130 GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, | 130 GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, |
| 131 ELFStreamer *ELFStr, VerboseMask Mask, | 131 ELFStreamer *ELFStr, VerboseMask Mask, |
| 132 TargetArch Arch, OptLevel Opt, | 132 TargetArch Arch, OptLevel Opt, |
| 133 IceString TestPrefix, const ClFlags &Flags) | 133 IceString TestPrefix, const ClFlags &Flags) |
| 134 : ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump), | 134 : ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump), |
| 135 StrEmit(OsEmit), VMask(Mask), Arch(Arch), Opt(Opt), | 135 StrEmit(OsEmit), VMask(Mask), Arch(Arch), Opt(Opt), |
| 136 TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter(), | 136 TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter(), |
| 137 CfgQ(/*MaxSize=*/Flags.getNumTranslationThreads(), | 137 OptQ(/*Sequential=*/Flags.isSequential(), |
| 138 /*Sequential=*/(Flags.getNumTranslationThreads() == 0)) { | 138 /*MaxSize=*/Flags.getNumTranslationThreads()), |
| 139 // EmitQ is allowed unlimited size. | |
| 140 EmitQ(/*Sequential=*/Flags.isSequential()) { | |
| 139 // Make sure thread_local fields are properly initialized before any | 141 // Make sure thread_local fields are properly initialized before any |
| 140 // accesses are made. Do this here instead of at the start of | 142 // accesses are made. Do this here instead of at the start of |
| 141 // main() so that all clients (e.g. unit tests) can benefit for | 143 // main() so that all clients (e.g. unit tests) can benefit for |
| 142 // free. | 144 // free. |
| 143 GlobalContext::TlsInit(); | 145 GlobalContext::TlsInit(); |
| 144 Cfg::TlsInit(); | 146 Cfg::TlsInit(); |
| 145 // Create a new ThreadContext for the current thread. No need to | 147 // Create a new ThreadContext for the current thread. No need to |
| 146 // lock AllThreadContexts at this point since no other threads have | 148 // lock AllThreadContexts at this point since no other threads have |
| 147 // access yet to this GlobalContext object. | 149 // access yet to this GlobalContext object. |
| 148 ThreadContext *MyTLS = new ThreadContext(); | 150 ThreadContext *MyTLS = new ThreadContext(); |
| 149 AllThreadContexts.push_back(MyTLS); | 151 AllThreadContexts.push_back(MyTLS); |
| 150 ICE_TLS_SET_FIELD(TLS, MyTLS); | 152 ICE_TLS_SET_FIELD(TLS, MyTLS); |
| 151 // Pre-register built-in stack names. | 153 // Pre-register built-in stack names. |
| 152 if (ALLOW_DUMP) { | 154 if (ALLOW_DUMP) { |
| 153 // TODO(stichnot): There needs to be a strong relationship between | 155 // TODO(stichnot): There needs to be a strong relationship between |
| 154 // the newTimerStackID() return values and TSK_Default/TSK_Funcs. | 156 // the newTimerStackID() return values and TSK_Default/TSK_Funcs. |
| 155 newTimerStackID("Total across all functions"); | 157 newTimerStackID("Total across all functions"); |
| 156 newTimerStackID("Per-function summary"); | 158 newTimerStackID("Per-function summary"); |
| 157 } | 159 } |
| 158 Timers.initInto(MyTLS->Timers); | 160 Timers.initInto(MyTLS->Timers); |
| 159 if (Flags.getUseELFWriter()) { | 161 if (Flags.getUseELFWriter()) { |
| 160 ObjectWriter.reset(new ELFObjectWriter(*this, *ELFStr)); | 162 ObjectWriter.reset(new ELFObjectWriter(*this, *ELFStr)); |
| 161 } | 163 } |
| 162 } | 164 } |
| 163 | 165 |
| 164 void GlobalContext::translateFunctions() { | 166 void GlobalContext::translateFunctions() { |
| 165 while (std::unique_ptr<Cfg> Func = cfgQueueBlockingPop()) { | 167 while (std::unique_ptr<Cfg> Func = optQueueBlockingPop()) { |
| 166 // Install Func in TLS for Cfg-specific container allocators. | 168 // Install Func in TLS for Cfg-specific container allocators. |
| 167 Cfg::setCurrentCfg(Func.get()); | 169 Cfg::setCurrentCfg(Func.get()); |
| 168 // Reset per-function stats being accumulated in TLS. | 170 // Reset per-function stats being accumulated in TLS. |
| 169 resetStats(); | 171 resetStats(); |
| 170 // Set verbose level to none if the current function does NOT | 172 // Set verbose level to none if the current function does NOT |
| 171 // match the -verbose-focus command-line option. | 173 // match the -verbose-focus command-line option. |
| 172 if (!matchSymbolName(Func->getFunctionName(), | 174 if (!matchSymbolName(Func->getFunctionName(), |
| 173 getFlags().getVerboseFocusOn())) | 175 getFlags().getVerboseFocusOn())) |
| 174 Func->setVerbose(IceV_None); | 176 Func->setVerbose(IceV_None); |
| 175 // Disable translation if -notranslate is specified, or if the | 177 // Disable translation if -notranslate is specified, or if the |
| 176 // current function matches the -translate-only option. If | 178 // current function matches the -translate-only option. If |
| 177 // translation is disabled, just dump the high-level IR and | 179 // translation is disabled, just dump the high-level IR and |
| 178 // continue. | 180 // continue. |
| 179 if (getFlags().getDisableTranslation() || | 181 if (getFlags().getDisableTranslation() || |
| 180 !matchSymbolName(Func->getFunctionName(), | 182 !matchSymbolName(Func->getFunctionName(), |
| 181 getFlags().getTranslateOnly())) { | 183 getFlags().getTranslateOnly())) { |
| 182 Func->dump(); | 184 Func->dump(); |
| 185 Cfg::setCurrentCfg(nullptr); | |
|
jvoung (off chromium)
2015/02/11 16:56:01
Could add a "continue;" here, and not have to inde
Jim Stichnoth
2015/02/11 21:52:58
Done.
| |
| 183 } else { | 186 } else { |
| 184 Func->translate(); | 187 Func->translate(); |
| 188 EmitterWorkItem *Item = nullptr; | |
| 185 if (Func->hasError()) { | 189 if (Func->hasError()) { |
| 186 getErrorStatus()->assign(EC_Translation); | 190 getErrorStatus()->assign(EC_Translation); |
| 187 OstreamLocker L(this); | 191 OstreamLocker L(this); |
| 188 getStrDump() << "ICE translation error: " << Func->getError() << "\n"; | 192 getStrDump() << "ICE translation error: " << Func->getError() << "\n"; |
| 193 Item = new EmitterWorkItem(Func->getSequenceNumber()); | |
| 189 } else { | 194 } else { |
| 190 if (getFlags().getUseIntegratedAssembler()) | 195 if (getFlags().getUseIntegratedAssembler()) { |
| 191 Func->emitIAS(); | 196 Func->emitIAS(); |
| 192 else | 197 // The Cfg has already emitted into the assembly buffer, so |
| 193 Func->emit(); | 198 // stats have been fully collected into this thread's TLS. |
| 194 // TODO(stichnot): actually add to emit queue | 199 // Dump them before TLS is reset for the next Cfg. |
| 200 dumpStats(Func->getFunctionName()); | |
| 201 Assembler *Asm = Func->releaseAssembler(); | |
| 202 // Copy relevant fields into Asm before Func is deleted. | |
| 203 Asm->setFunctionName(Func->getFunctionName()); | |
| 204 Asm->setInternal(Func->getInternal()); | |
| 205 Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); | |
| 206 } else { | |
| 207 // The Cfg has not been emitted yet, so stats are not ready | |
| 208 // to be dumped. | |
| 209 Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); | |
| 210 } | |
| 195 } | 211 } |
| 212 Cfg::setCurrentCfg(nullptr); | |
| 213 assert(Item); | |
| 214 emitQueueBlockingPush(Item); | |
| 215 } | |
| 216 // The Cfg now gets deleted as Func goes out of scope. | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 namespace { | |
| 221 | |
| 222 void lowerGlobals(GlobalContext *Ctx, | |
| 223 std::unique_ptr<VariableDeclarationList> VariableDeclarations, | |
| 224 TargetDataLowering *DataLowering) { | |
| 225 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); | |
| 226 bool DisableTranslation = Ctx->getFlags().getDisableTranslation(); | |
| 227 const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getVerbose() && | |
| 228 Ctx->getFlags().getVerboseFocusOn().empty(); | |
| 229 if (Ctx->getFlags().getUseELFWriter()) { | |
| 230 // Dump all globals if requested, but don't interleave w/ emission. | |
| 231 if (DumpGlobalVariables) { | |
| 232 OstreamLocker L(Ctx); | |
| 233 Ostream &Stream = Ctx->getStrDump(); | |
| 234 for (const Ice::VariableDeclaration *Global : | |
| 235 *VariableDeclarations.get()) { | |
|
jvoung (off chromium)
2015/02/11 16:56:00
Does unique_ptr have an "operator*", so you wouldn
Jim Stichnoth
2015/02/11 21:52:58
It does, and this would change it to **VariableDec
Karl
2015/02/11 21:58:20
Actually no. It would change to *VariableDeclarati
Jim Stichnoth
2015/02/11 23:01:07
Oops, you're right.
I made that change (in 3 plac
| |
| 236 Global->dump(Ctx, Stream); | |
| 237 } | |
| 238 } | |
| 239 DataLowering->lowerGlobalsELF(*VariableDeclarations.get()); // XXX | |
|
jvoung (off chromium)
2015/02/11 16:56:01
XXX ?
Also, same question about *p.get() here and
Jim Stichnoth
2015/02/11 21:52:58
Oops, I meant to clean that up, because it seemed
| |
| 240 } else { | |
| 241 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); | |
| 242 OstreamLocker L(Ctx); | |
| 243 Ostream &Stream = Ctx->getStrDump(); | |
| 244 for (const Ice::VariableDeclaration *Global : *VariableDeclarations.get()) { | |
| 245 // Interleave dump output w/ emit output. | |
| 246 if (DumpGlobalVariables) | |
| 247 Global->dump(Ctx, Stream); | |
| 248 if (!DisableTranslation && | |
| 249 GlobalContext::matchSymbolName(Global->getName(), TranslateOnly)) | |
| 250 DataLowering->lowerGlobal(*Global); | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 // Ensure Pending is large enough that Pending[Index] is valid. | |
| 256 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { | |
| 257 if (Index >= Pending.size()) | |
| 258 Pending.resize(Index + 1); | |
| 259 } | |
| 260 | |
| 261 } // end of anonymous namespace | |
| 262 | |
| 263 void GlobalContext::emitItems() { | |
| 264 const bool Threaded = !getFlags().isSequential(); | |
| 265 // Pending is a vector containing the reassembled, ordered list of | |
| 266 // work items. When we're ready for the next item, we first check | |
| 267 // whether it's in the Pending list. If not, we take an item from | |
| 268 // the work queue, and if it's not the item we're waiting for, we | |
| 269 // insert it into Pending and repeat. The work item is deleted | |
| 270 // after it is processed. | |
| 271 std::vector<EmitterWorkItem *> Pending; | |
| 272 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); | |
| 273 while (true) { | |
| 274 resizePending(Pending, DesiredSequenceNumber); | |
| 275 // See if Pending contains DesiredSequenceNumber. | |
| 276 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; | |
| 277 if (RawItem == nullptr) | |
| 278 RawItem = emitQueueBlockingPop(); | |
| 279 if (RawItem == nullptr) | |
| 280 return; | |
| 281 uint32_t ItemSeq = RawItem->getSequenceNumber(); | |
| 282 if (Threaded && ItemSeq != DesiredSequenceNumber) { | |
| 283 resizePending(Pending, ItemSeq); | |
| 284 Pending[ItemSeq] = RawItem; | |
| 285 continue; | |
| 286 } | |
| 287 | |
| 288 std::unique_ptr<EmitterWorkItem> Item(RawItem); | |
| 289 ++DesiredSequenceNumber; | |
| 290 switch (Item->getKind()) { | |
| 291 case EmitterWorkItem::WI_Nop: | |
| 292 break; | |
| 293 case EmitterWorkItem::WI_GlobalInits: { | |
| 294 lowerGlobals(this, Item->getGlobalInits(), | |
| 295 TargetDataLowering::createLowering(this).get()); | |
| 296 } break; | |
| 297 case EmitterWorkItem::WI_Asm: { | |
| 298 std::unique_ptr<Assembler> Asm = Item->getAsm(); | |
| 299 Asm->alignFunction(); | |
| 300 IceString MangledName = mangleName(Asm->getFunctionName()); | |
| 301 if (getFlags().getUseELFWriter()) { | |
| 302 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), | |
| 303 Asm.get()); | |
| 304 } else { | |
| 305 OstreamLocker L(this); | |
| 306 Cfg::emitTextHeader(MangledName, this, Asm.get()); | |
| 307 Asm->emitIASBytes(this); | |
| 308 } | |
| 309 } break; | |
| 310 case EmitterWorkItem::WI_Cfg: { | |
| 311 if (!ALLOW_DUMP) | |
| 312 llvm::report_fatal_error("WI_Cfg work item created inappropriately"); | |
| 313 assert(!getFlags().getUseIntegratedAssembler()); | |
| 314 std::unique_ptr<Cfg> Func = Item->getCfg(); | |
| 315 // Unfortunately, we have to temporarily install the Cfg in TLS | |
| 316 // because Variable::asType() uses the allocator to create the | |
| 317 // differently-typed copy. | |
| 318 Cfg::setCurrentCfg(Func.get()); | |
| 319 Func->emit(); | |
| 320 Cfg::setCurrentCfg(nullptr); | |
| 196 dumpStats(Func->getFunctionName()); | 321 dumpStats(Func->getFunctionName()); |
| 322 } break; | |
| 197 } | 323 } |
| 198 Cfg::setCurrentCfg(nullptr); | |
| 199 // The Cfg now gets deleted as Func goes out of scope. | |
| 200 } | 324 } |
| 201 } | 325 } |
| 202 | 326 |
| 203 // Scan a string for S[0-9A-Z]*_ patterns and replace them with | 327 // Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| 204 // S<num>_ where <num> is the next base-36 value. If a type name | 328 // S<num>_ where <num> is the next base-36 value. If a type name |
| 205 // legitimately contains that pattern, then the substitution will be | 329 // legitimately contains that pattern, then the substitution will be |
| 206 // made in error and most likely the link will fail. In this case, | 330 // made in error and most likely the link will fail. In this case, |
| 207 // the test classes can be rewritten not to use that pattern, which is | 331 // the test classes can be rewritten not to use that pattern, which is |
| 208 // much simpler and more reliable than implementing a full demangling | 332 // much simpler and more reliable than implementing a full demangling |
| 209 // parser. Another substitution-in-error may occur if a type | 333 // parser. Another substitution-in-error may occur if a type |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 Timers->at(StackID).reset(); | 667 Timers->at(StackID).reset(); |
| 544 } | 668 } |
| 545 | 669 |
| 546 void GlobalContext::setTimerName(TimerStackIdT StackID, | 670 void GlobalContext::setTimerName(TimerStackIdT StackID, |
| 547 const IceString &NewName) { | 671 const IceString &NewName) { |
| 548 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; | 672 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
| 549 assert(StackID < Timers->size()); | 673 assert(StackID < Timers->size()); |
| 550 Timers->at(StackID).setName(NewName); | 674 Timers->at(StackID).setName(NewName); |
| 551 } | 675 } |
| 552 | 676 |
| 553 // Note: cfgQueueBlockingPush and cfgQueueBlockingPop use unique_ptr | 677 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr |
| 554 // at the interface to take and transfer ownership, but they | 678 // at the interface to take and transfer ownership, but they |
| 555 // internally store the raw Cfg pointer in the work queue. This | 679 // internally store the raw Cfg pointer in the work queue. This |
| 556 // allows e.g. future queue optimizations such as the use of atomics | 680 // allows e.g. future queue optimizations such as the use of atomics |
| 557 // to modify queue elements. | 681 // to modify queue elements. |
| 558 void GlobalContext::cfgQueueBlockingPush(std::unique_ptr<Cfg> Func) { | 682 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { |
| 559 CfgQ.blockingPush(Func.release()); | 683 assert(Func); |
| 684 OptQ.blockingPush(Func.release()); | |
| 685 if (getFlags().isSequential()) | |
| 686 translateFunctions(); | |
| 560 } | 687 } |
| 561 | 688 |
| 562 std::unique_ptr<Cfg> GlobalContext::cfgQueueBlockingPop() { | 689 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { |
| 563 return std::unique_ptr<Cfg>(CfgQ.blockingPop()); | 690 return std::unique_ptr<Cfg>(OptQ.blockingPop()); |
| 691 } | |
| 692 | |
| 693 void GlobalContext::emitQueueBlockingPush(EmitterWorkItem *Item) { | |
| 694 assert(Item); | |
| 695 EmitQ.blockingPush(Item); | |
| 696 if (getFlags().isSequential()) | |
| 697 emitItems(); | |
| 698 } | |
| 699 | |
| 700 EmitterWorkItem *GlobalContext::emitQueueBlockingPop() { | |
| 701 return EmitQ.blockingPop(); | |
| 564 } | 702 } |
| 565 | 703 |
| 566 void GlobalContext::dumpStats(const IceString &Name, bool Final) { | 704 void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
| 567 if (!getFlags().getDumpStats()) | 705 if (!getFlags().getDumpStats()) |
| 568 return; | 706 return; |
| 569 OstreamLocker OL(this); | 707 OstreamLocker OL(this); |
| 570 if (Final) { | 708 if (Final) { |
| 571 getStatsCumulative()->dump(Name, getStrDump()); | 709 getStatsCumulative()->dump(Name, getStrDump()); |
| 572 } else { | 710 } else { |
| 573 ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump()); | 711 ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump()); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 602 Ctx = Func->getContext(); | 740 Ctx = Func->getContext(); |
| 603 Active = | 741 Active = |
| 604 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); | 742 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
| 605 if (Active) | 743 if (Active) |
| 606 Ctx->pushTimer(ID, StackID); | 744 Ctx->pushTimer(ID, StackID); |
| 607 } | 745 } |
| 608 | 746 |
| 609 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); | 747 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
| 610 | 748 |
| 611 } // end of namespace Ice | 749 } // end of namespace Ice |
| OLD | NEW |