Chromium Code Reviews| Index: src/IceGlobalContext.cpp |
| diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp |
| index 4324f97f442b08ec1731ad996e28898a277766a4..b5efb285e13e8bf9f804e8608f3be4851ee695d6 100644 |
| --- a/src/IceGlobalContext.cpp |
| +++ b/src/IceGlobalContext.cpp |
| @@ -135,7 +135,9 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, |
| StrEmit(OsEmit), VMask(Mask), Arch(Arch), Opt(Opt), |
| TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter(), |
| CfgQ(/*MaxSize=*/Flags.NumTranslationThreads, |
| - /*Sequential=*/(Flags.NumTranslationThreads == 0)) { |
| + /*Sequential=*/(Flags.NumTranslationThreads == 0)), |
| + EmitQ(/*MaxSize=*/Flags.NumTranslationThreads, |
|
JF
2015/02/08 00:29:47
Translation an emit thread numbers should be indep
Jim Stichnoth
2015/02/08 17:11:23
Oops, cargo-cult error.
The Sequential logic is t
|
| + /*Sequential=*/(Flags.NumTranslationThreads == 0)) { |
| // Make sure thread_local fields are properly initialized before any |
| // accesses are made. Do this here instead of at the start of |
| // main() so that all clients (e.g. unit tests) can benefit for |
| @@ -178,26 +180,145 @@ void GlobalContext::translateFunctions() { |
| if (getFlags().DisableTranslation || |
| !matchSymbolName(Func->getFunctionName(), getFlags().TranslateOnly)) { |
| Func->dump(); |
| + Cfg::setCurrentCfg(nullptr); |
| } else { |
| Func->translate(); |
| + EmitterWorkItem *Item = nullptr; |
| if (Func->hasError()) { |
| getErrorStatus()->assign(EC_Translation); |
| OstreamLocker L(this); |
| getStrDump() << "ICE translation error: " << Func->getError() << "\n"; |
| + Item = new EmitterWorkItem(Func->getSequenceNumber()); |
| } else { |
| - if (getFlags().UseIntegratedAssembler) |
| + if (getFlags().UseIntegratedAssembler) { |
| Func->emitIAS(); |
| - else |
| - Func->emit(); |
| - // TODO(stichnot): actually add to emit queue |
| + // The Cfg has already emitted into the assembly buffer, so |
| + // stats have been fully collected into this thread's TLS. |
| + // Dump them before TLS is reset for the next Cfg. |
| + dumpStats(Func->getFunctionName()); |
| + Assembler *Asm = Func->releaseAssembler(); |
| + // Copy relevant fields into Asm before Func is deleted. |
| + Asm->setFunctionName(Func->getFunctionName()); |
| + Asm->setInternal(Func->getInternal()); |
| + Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); |
| + } else { |
| + // The Cfg has not been emitted yet, so stats are not ready |
| + // to be dumped. |
| + Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); |
| + } |
| } |
| - dumpStats(Func->getFunctionName()); |
| + Cfg::setCurrentCfg(nullptr); |
| + assert(Item); |
| + emitQueueBlockingPush(Item); |
| } |
| - Cfg::setCurrentCfg(nullptr); |
| // The Cfg now gets deleted as Func goes out of scope. |
| } |
| } |
| +namespace { |
| + |
| +void lowerGlobals(GlobalContext *Ctx, |
|
Jim Stichnoth
2015/02/07 14:53:07
This is moved largely unchanged from Translator::l
|
| + VariableDeclarationList *VariableDeclarations, |
| + TargetDataLowering *DataLowering) { |
| + TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); |
| + bool DisableTranslation = Ctx->getFlags().DisableTranslation; |
| + const bool DumpGlobalVariables = |
| + ALLOW_DUMP && Ctx->getVerbose() && Ctx->getFlags().VerboseFocusOn.empty(); |
| + if (Ctx->getFlags().UseELFWriter) { |
| + // Dump all globals if requested, but don't interleave w/ emission. |
| + if (DumpGlobalVariables) { |
| + OstreamLocker L(Ctx); |
| + Ostream &Stream = Ctx->getStrDump(); |
| + for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { |
| + Global->dump(Ctx, Stream); |
| + } |
| + } |
| + DataLowering->lowerGlobalsELF(*VariableDeclarations); |
| + } else { |
| + const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly; |
| + OstreamLocker L(Ctx); |
| + Ostream &Stream = Ctx->getStrDump(); |
| + for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { |
| + // Interleave dump output w/ emit output. |
| + if (DumpGlobalVariables) |
| + Global->dump(Ctx, Stream); |
| + if (!DisableTranslation && |
| + GlobalContext::matchSymbolName(Global->getName(), TranslateOnly)) |
| + DataLowering->lowerGlobal(*Global); |
| + } |
| + } |
| +} |
| + |
| +// Ensure Pending is large enough that Pending[Index] is valid. |
| +void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { |
| + if (Index >= Pending.size()) |
| + Pending.resize(Index + 1); |
| +} |
| + |
| +} // end of anonymous namespace |
| + |
| +void GlobalContext::emitItems() { |
| + const bool Threaded = getFlags().NumTranslationThreads; |
| + // Pending is a vector containing the reassembled, ordered list of |
| + // work items. When we're ready for the next item, we first check |
| + // whether it's in the Pending list. If not, we take an item from |
| + // the work queue, and if it's not the item we're waiting for, we |
| + // insert it into Pending and repeat. The work item is deleted |
| + // after it is processed. |
| + std::vector<EmitterWorkItem *> Pending; |
| + uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); |
| + while (true) { |
| + resizePending(Pending, DesiredSequenceNumber); |
| + // See if Pending contains DesiredSequenceNumber. |
| + EmitterWorkItem *Item = Pending[DesiredSequenceNumber]; |
| + if (Item == nullptr) |
| + Item = emitQueueBlockingPop(); |
| + if (Item == nullptr) |
| + return; |
| + uint32_t ItemSeq = Item->getSequenceNumber(); |
| + if (Threaded && ItemSeq != DesiredSequenceNumber) { |
| + resizePending(Pending, ItemSeq); |
| + Pending[ItemSeq] = Item; |
| + continue; |
| + } |
| + |
| + ++DesiredSequenceNumber; |
| + switch (Item->getKind()) { |
| + case EmitterWorkItem::WI_Nop: |
| + break; |
| + case EmitterWorkItem::WI_GlobalInits: { |
| + lowerGlobals(this, Item->getGlobalInits(), |
| + TargetDataLowering::createLowering(this).get()); |
| + } break; |
| + case EmitterWorkItem::WI_Asm: { |
| + Assembler *Asm = Item->getAsm(); |
| + Asm->alignFunction(); |
| + IceString MangledName = mangleName(Asm->getFunctionName()); |
| + if (getFlags().UseELFWriter) { |
| + getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), |
| + Asm); |
| + } else { |
| + OstreamLocker L(this); |
| + Cfg::emitTextHeader(MangledName, this, Asm); |
| + Asm->emitIASBytes(this); |
| + } |
| + } break; |
| + case EmitterWorkItem::WI_Cfg: { |
| + assert(!getFlags().UseIntegratedAssembler); |
| + Cfg *Func = Item->getCfg(); |
| + // Unfortunately, we have to temporarily install the Cfg in TLS |
| + // because Variable::asType() uses the allocator to create the |
| + // differently-typed copy. |
| + Cfg::setCurrentCfg(Func); |
| + Func->emit(); |
| + Cfg::setCurrentCfg(nullptr); |
| + dumpStats(Func->getFunctionName()); |
| + } break; |
| + } |
| + delete Item; |
| + } |
| +} |
| + |
| // Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| // S<num>_ where <num> is the next base-36 value. If a type name |
| // legitimately contains that pattern, then the substitution will be |
| @@ -554,13 +675,27 @@ void GlobalContext::setTimerName(TimerStackIdT StackID, |
| // allows e.g. future queue optimizations such as the use of atomics |
| // to modify queue elements. |
| void GlobalContext::cfgQueueBlockingPush(std::unique_ptr<Cfg> Func) { |
| + assert(Func); |
| CfgQ.blockingPush(Func.release()); |
| + if (getFlags().NumTranslationThreads == 0) |
| + translateFunctions(); |
| } |
| std::unique_ptr<Cfg> GlobalContext::cfgQueueBlockingPop() { |
| return std::unique_ptr<Cfg>(CfgQ.blockingPop()); |
| } |
| +void GlobalContext::emitQueueBlockingPush(EmitterWorkItem *Item) { |
| + assert(Item); |
| + EmitQ.blockingPush(Item); |
| + if (getFlags().NumTranslationThreads == 0) |
| + emitItems(); |
| +} |
| + |
| +EmitterWorkItem *GlobalContext::emitQueueBlockingPop() { |
| + return EmitQ.blockingPop(); |
| +} |
| + |
| void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
| if (!ALLOW_DUMP || !getFlags().DumpStats) |
| return; |
| @@ -603,6 +738,15 @@ void TimerMarker::pushCfg(const Cfg *Func) { |
| Ctx->pushTimer(ID, StackID); |
| } |
| +EmitterWorkItem::~EmitterWorkItem() { |
| + // TODO(kschimpf,stichnot): Delete GlobalInits once it is managed in |
| + // the parser as a unique_ptr. |
| + |
| + // delete GlobalInits; |
| + delete Function; |
| + delete RawFunc; |
| +} |
| + |
| ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
| } // end of namespace Ice |