Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: src/IceGlobalContext.cpp

Issue 876083007: Subzero: Emit functions and global initializers in a separate thread. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: More code review changes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/IceGlobalContext.h ('k') | src/IceTargetLowering.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/IceGlobalContext.cpp
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 4324f97f442b08ec1731ad996e28898a277766a4..a03b1e95eeabbf4acb0951b744a15f3742b22f63 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -134,8 +134,10 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit,
: ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump),
StrEmit(OsEmit), VMask(Mask), Arch(Arch), Opt(Opt),
TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter(),
- CfgQ(/*MaxSize=*/Flags.NumTranslationThreads,
- /*Sequential=*/(Flags.NumTranslationThreads == 0)) {
+ OptQ(/*Sequential=*/(Flags.NumTranslationThreads == 0),
+ /*MaxSize=*/Flags.NumTranslationThreads),
+ // EmitQ is allowed unlimited size.
+ EmitQ(/*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
@@ -162,7 +164,7 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit,
}
void GlobalContext::translateFunctions() {
- while (std::unique_ptr<Cfg> Func = cfgQueueBlockingPop()) {
+ while (std::unique_ptr<Cfg> Func = optQueueBlockingPop()) {
// Install Func in TLS for Cfg-specific container allocators.
Cfg::setCurrentCfg(Func.get());
// Reset per-function stats being accumulated in TLS.
@@ -178,26 +180,147 @@ 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,
+ 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: {
+ if (!ALLOW_DUMP)
+ llvm::report_fatal_error("WI_Cfg work item created inappropriately");
+ 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
@@ -548,17 +671,31 @@ void GlobalContext::setTimerName(TimerStackIdT StackID,
Timers->at(StackID).setName(NewName);
}
-// Note: cfgQueueBlockingPush and cfgQueueBlockingPop use unique_ptr
+// Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr
// at the interface to take and transfer ownership, but they
// internally store the raw Cfg pointer in the work queue. This
// allows e.g. future queue optimizations such as the use of atomics
// to modify queue elements.
-void GlobalContext::cfgQueueBlockingPush(std::unique_ptr<Cfg> Func) {
- CfgQ.blockingPush(Func.release());
+void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) {
+ assert(Func);
+ OptQ.blockingPush(Func.release());
+ if (getFlags().NumTranslationThreads == 0)
+ translateFunctions();
}
-std::unique_ptr<Cfg> GlobalContext::cfgQueueBlockingPop() {
- return std::unique_ptr<Cfg>(CfgQ.blockingPop());
+std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() {
+ return std::unique_ptr<Cfg>(OptQ.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) {
@@ -603,6 +740,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
« no previous file with comments | « src/IceGlobalContext.h ('k') | src/IceTargetLowering.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698