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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « src/IceGlobalContext.h ('k') | src/IceTargetLowering.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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.NumTranslationThreads, 137 OptQ(/*Sequential=*/(Flags.NumTranslationThreads == 0),
138 /*Sequential=*/(Flags.NumTranslationThreads == 0)) { 138 /*MaxSize=*/Flags.NumTranslationThreads),
139 // EmitQ is allowed unlimited size.
140 EmitQ(/*Sequential=*/(Flags.NumTranslationThreads == 0)) {
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.UseELFWriter) { 161 if (Flags.UseELFWriter) {
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(), getFlags().VerboseFocusOn)) 174 if (!matchSymbolName(Func->getFunctionName(), getFlags().VerboseFocusOn))
173 Func->setVerbose(IceV_None); 175 Func->setVerbose(IceV_None);
174 // Disable translation if -notranslate is specified, or if the 176 // Disable translation if -notranslate is specified, or if the
175 // current function matches the -translate-only option. If 177 // current function matches the -translate-only option. If
176 // translation is disabled, just dump the high-level IR and 178 // translation is disabled, just dump the high-level IR and
177 // continue. 179 // continue.
178 if (getFlags().DisableTranslation || 180 if (getFlags().DisableTranslation ||
179 !matchSymbolName(Func->getFunctionName(), getFlags().TranslateOnly)) { 181 !matchSymbolName(Func->getFunctionName(), getFlags().TranslateOnly)) {
180 Func->dump(); 182 Func->dump();
183 Cfg::setCurrentCfg(nullptr);
181 } else { 184 } else {
182 Func->translate(); 185 Func->translate();
186 EmitterWorkItem *Item = nullptr;
183 if (Func->hasError()) { 187 if (Func->hasError()) {
184 getErrorStatus()->assign(EC_Translation); 188 getErrorStatus()->assign(EC_Translation);
185 OstreamLocker L(this); 189 OstreamLocker L(this);
186 getStrDump() << "ICE translation error: " << Func->getError() << "\n"; 190 getStrDump() << "ICE translation error: " << Func->getError() << "\n";
191 Item = new EmitterWorkItem(Func->getSequenceNumber());
187 } else { 192 } else {
188 if (getFlags().UseIntegratedAssembler) 193 if (getFlags().UseIntegratedAssembler) {
189 Func->emitIAS(); 194 Func->emitIAS();
190 else 195 // The Cfg has already emitted into the assembly buffer, so
191 Func->emit(); 196 // stats have been fully collected into this thread's TLS.
192 // TODO(stichnot): actually add to emit queue 197 // Dump them before TLS is reset for the next Cfg.
198 dumpStats(Func->getFunctionName());
199 Assembler *Asm = Func->releaseAssembler();
200 // Copy relevant fields into Asm before Func is deleted.
201 Asm->setFunctionName(Func->getFunctionName());
202 Asm->setInternal(Func->getInternal());
203 Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm);
204 } else {
205 // The Cfg has not been emitted yet, so stats are not ready
206 // to be dumped.
207 Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release());
208 }
193 } 209 }
210 Cfg::setCurrentCfg(nullptr);
211 assert(Item);
212 emitQueueBlockingPush(Item);
213 }
214 // The Cfg now gets deleted as Func goes out of scope.
215 }
216 }
217
218 namespace {
219
220 void lowerGlobals(GlobalContext *Ctx,
221 VariableDeclarationList *VariableDeclarations,
222 TargetDataLowering *DataLowering) {
223 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
224 bool DisableTranslation = Ctx->getFlags().DisableTranslation;
225 const bool DumpGlobalVariables =
226 ALLOW_DUMP && Ctx->getVerbose() && Ctx->getFlags().VerboseFocusOn.empty();
227 if (Ctx->getFlags().UseELFWriter) {
228 // Dump all globals if requested, but don't interleave w/ emission.
229 if (DumpGlobalVariables) {
230 OstreamLocker L(Ctx);
231 Ostream &Stream = Ctx->getStrDump();
232 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) {
233 Global->dump(Ctx, Stream);
234 }
235 }
236 DataLowering->lowerGlobalsELF(*VariableDeclarations);
237 } else {
238 const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly;
239 OstreamLocker L(Ctx);
240 Ostream &Stream = Ctx->getStrDump();
241 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) {
242 // Interleave dump output w/ emit output.
243 if (DumpGlobalVariables)
244 Global->dump(Ctx, Stream);
245 if (!DisableTranslation &&
246 GlobalContext::matchSymbolName(Global->getName(), TranslateOnly))
247 DataLowering->lowerGlobal(*Global);
248 }
249 }
250 }
251
252 // Ensure Pending is large enough that Pending[Index] is valid.
253 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) {
254 if (Index >= Pending.size())
255 Pending.resize(Index + 1);
256 }
257
258 } // end of anonymous namespace
259
260 void GlobalContext::emitItems() {
261 const bool Threaded = getFlags().NumTranslationThreads;
262 // Pending is a vector containing the reassembled, ordered list of
263 // work items. When we're ready for the next item, we first check
264 // whether it's in the Pending list. If not, we take an item from
265 // the work queue, and if it's not the item we're waiting for, we
266 // insert it into Pending and repeat. The work item is deleted
267 // after it is processed.
268 std::vector<EmitterWorkItem *> Pending;
269 uint32_t DesiredSequenceNumber = getFirstSequenceNumber();
270 while (true) {
271 resizePending(Pending, DesiredSequenceNumber);
272 // See if Pending contains DesiredSequenceNumber.
273 EmitterWorkItem *Item = Pending[DesiredSequenceNumber];
274 if (Item == nullptr)
275 Item = emitQueueBlockingPop();
276 if (Item == nullptr)
277 return;
278 uint32_t ItemSeq = Item->getSequenceNumber();
279 if (Threaded && ItemSeq != DesiredSequenceNumber) {
280 resizePending(Pending, ItemSeq);
281 Pending[ItemSeq] = Item;
282 continue;
283 }
284
285 ++DesiredSequenceNumber;
286 switch (Item->getKind()) {
287 case EmitterWorkItem::WI_Nop:
288 break;
289 case EmitterWorkItem::WI_GlobalInits: {
290 lowerGlobals(this, Item->getGlobalInits(),
291 TargetDataLowering::createLowering(this).get());
292 } break;
293 case EmitterWorkItem::WI_Asm: {
294 Assembler *Asm = Item->getAsm();
295 Asm->alignFunction();
296 IceString MangledName = mangleName(Asm->getFunctionName());
297 if (getFlags().UseELFWriter) {
298 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(),
299 Asm);
300 } else {
301 OstreamLocker L(this);
302 Cfg::emitTextHeader(MangledName, this, Asm);
303 Asm->emitIASBytes(this);
304 }
305 } break;
306 case EmitterWorkItem::WI_Cfg: {
307 if (!ALLOW_DUMP)
308 llvm::report_fatal_error("WI_Cfg work item created inappropriately");
309 assert(!getFlags().UseIntegratedAssembler);
310 Cfg *Func = Item->getCfg();
311 // Unfortunately, we have to temporarily install the Cfg in TLS
312 // because Variable::asType() uses the allocator to create the
313 // differently-typed copy.
314 Cfg::setCurrentCfg(Func);
315 Func->emit();
316 Cfg::setCurrentCfg(nullptr);
194 dumpStats(Func->getFunctionName()); 317 dumpStats(Func->getFunctionName());
318 } break;
195 } 319 }
196 Cfg::setCurrentCfg(nullptr); 320 delete Item;
197 // The Cfg now gets deleted as Func goes out of scope.
198 } 321 }
199 } 322 }
200 323
201 // Scan a string for S[0-9A-Z]*_ patterns and replace them with 324 // Scan a string for S[0-9A-Z]*_ patterns and replace them with
202 // S<num>_ where <num> is the next base-36 value. If a type name 325 // S<num>_ where <num> is the next base-36 value. If a type name
203 // legitimately contains that pattern, then the substitution will be 326 // legitimately contains that pattern, then the substitution will be
204 // made in error and most likely the link will fail. In this case, 327 // made in error and most likely the link will fail. In this case,
205 // the test classes can be rewritten not to use that pattern, which is 328 // the test classes can be rewritten not to use that pattern, which is
206 // much simpler and more reliable than implementing a full demangling 329 // much simpler and more reliable than implementing a full demangling
207 // parser. Another substitution-in-error may occur if a type 330 // parser. Another substitution-in-error may occur if a type
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 Timers->at(StackID).reset(); 664 Timers->at(StackID).reset();
542 } 665 }
543 666
544 void GlobalContext::setTimerName(TimerStackIdT StackID, 667 void GlobalContext::setTimerName(TimerStackIdT StackID,
545 const IceString &NewName) { 668 const IceString &NewName) {
546 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; 669 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers;
547 assert(StackID < Timers->size()); 670 assert(StackID < Timers->size());
548 Timers->at(StackID).setName(NewName); 671 Timers->at(StackID).setName(NewName);
549 } 672 }
550 673
551 // Note: cfgQueueBlockingPush and cfgQueueBlockingPop use unique_ptr 674 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr
552 // at the interface to take and transfer ownership, but they 675 // at the interface to take and transfer ownership, but they
553 // internally store the raw Cfg pointer in the work queue. This 676 // internally store the raw Cfg pointer in the work queue. This
554 // allows e.g. future queue optimizations such as the use of atomics 677 // allows e.g. future queue optimizations such as the use of atomics
555 // to modify queue elements. 678 // to modify queue elements.
556 void GlobalContext::cfgQueueBlockingPush(std::unique_ptr<Cfg> Func) { 679 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) {
557 CfgQ.blockingPush(Func.release()); 680 assert(Func);
681 OptQ.blockingPush(Func.release());
682 if (getFlags().NumTranslationThreads == 0)
683 translateFunctions();
558 } 684 }
559 685
560 std::unique_ptr<Cfg> GlobalContext::cfgQueueBlockingPop() { 686 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() {
561 return std::unique_ptr<Cfg>(CfgQ.blockingPop()); 687 return std::unique_ptr<Cfg>(OptQ.blockingPop());
688 }
689
690 void GlobalContext::emitQueueBlockingPush(EmitterWorkItem *Item) {
691 assert(Item);
692 EmitQ.blockingPush(Item);
693 if (getFlags().NumTranslationThreads == 0)
694 emitItems();
695 }
696
697 EmitterWorkItem *GlobalContext::emitQueueBlockingPop() {
698 return EmitQ.blockingPop();
562 } 699 }
563 700
564 void GlobalContext::dumpStats(const IceString &Name, bool Final) { 701 void GlobalContext::dumpStats(const IceString &Name, bool Final) {
565 if (!ALLOW_DUMP || !getFlags().DumpStats) 702 if (!ALLOW_DUMP || !getFlags().DumpStats)
566 return; 703 return;
567 OstreamLocker OL(this); 704 OstreamLocker OL(this);
568 if (Final) { 705 if (Final) {
569 getStatsCumulative()->dump(Name, getStrDump()); 706 getStatsCumulative()->dump(Name, getStrDump());
570 } else { 707 } else {
571 ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump()); 708 ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump());
(...skipping 24 matching lines...) Expand all
596 Ctx->pushTimer(ID, StackID); 733 Ctx->pushTimer(ID, StackID);
597 } 734 }
598 735
599 void TimerMarker::pushCfg(const Cfg *Func) { 736 void TimerMarker::pushCfg(const Cfg *Func) {
600 Ctx = Func->getContext(); 737 Ctx = Func->getContext();
601 Active = Func->getFocusedTiming() || Ctx->getFlags().SubzeroTimingEnabled; 738 Active = Func->getFocusedTiming() || Ctx->getFlags().SubzeroTimingEnabled;
602 if (Active) 739 if (Active)
603 Ctx->pushTimer(ID, StackID); 740 Ctx->pushTimer(ID, StackID);
604 } 741 }
605 742
743 EmitterWorkItem::~EmitterWorkItem() {
744 // TODO(kschimpf,stichnot): Delete GlobalInits once it is managed in
745 // the parser as a unique_ptr.
746
747 // delete GlobalInits;
748 delete Function;
749 delete RawFunc;
750 }
751
606 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); 752 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS);
607 753
608 } // end of namespace Ice 754 } // end of namespace Ice
OLDNEW
« 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