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

Side by Side Diff: src/IceGlobalContext.cpp

Issue 916653004: 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: Set ias=1 for unit tests to avoid failure in the MINIMAL build 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
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.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
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
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
OLDNEW
« no previous file with comments | « src/IceGlobalContext.h ('k') | src/IceTargetLowering.h » ('j') | src/IceTargetLowering.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698