OLD | NEW |
1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===// | 1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===// |
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 /// \file | 10 /// \file |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "IceRNG.h" | 22 #include "IceRNG.h" |
23 #include "IceStringPool.h" | 23 #include "IceStringPool.h" |
24 #include "IceSwitchLowering.h" | 24 #include "IceSwitchLowering.h" |
25 #include "IceTargetLowering.def" | 25 #include "IceTargetLowering.def" |
26 #include "IceThreading.h" | 26 #include "IceThreading.h" |
27 #include "IceTimerTree.h" | 27 #include "IceTimerTree.h" |
28 #include "IceTypes.h" | 28 #include "IceTypes.h" |
29 #include "IceUtils.h" | 29 #include "IceUtils.h" |
30 | 30 |
31 #include <array> | 31 #include <array> |
| 32 #include <atomic> |
32 #include <cassert> | 33 #include <cassert> |
33 #include <functional> | 34 #include <functional> |
34 #include <memory> | 35 #include <memory> |
35 #include <mutex> | 36 #include <mutex> |
36 #include <thread> | 37 #include <thread> |
37 #include <type_traits> | 38 #include <type_traits> |
38 #include <utility> | 39 #include <utility> |
39 #include <vector> | 40 #include <vector> |
40 | 41 |
41 namespace Ice { | 42 namespace Ice { |
42 | 43 |
43 class ClFlags; | 44 class ClFlags; |
44 class ConstantPool; | 45 class ConstantPool; |
45 class EmitterWorkItem; | 46 class EmitterWorkItem; |
46 class FuncSigType; | 47 class FuncSigType; |
47 | 48 |
48 // Runtime helper function IDs | 49 // Runtime helper function IDs |
49 | 50 |
50 enum class RuntimeHelper { | 51 enum class RuntimeHelper { |
51 #define X(Tag, Name) H_##Tag, | 52 #define X(Tag, Name) H_##Tag, |
52 RUNTIME_HELPER_FUNCTIONS_TABLE | 53 RUNTIME_HELPER_FUNCTIONS_TABLE |
53 #undef X | 54 #undef X |
54 H_Num | 55 H_Num |
55 }; | 56 }; |
56 | 57 |
| 58 /// OptWorkItem is a simple wrapper used to pass parse information on a function |
| 59 /// block, to a translator thread. |
| 60 class OptWorkItem { |
| 61 OptWorkItem(const OptWorkItem &) = delete; |
| 62 OptWorkItem &operator=(const OptWorkItem &) = delete; |
| 63 |
| 64 public: |
| 65 // Get the Cfg for the funtion to translate. |
| 66 virtual std::unique_ptr<Cfg> getParsedCfg() = 0; |
| 67 virtual ~OptWorkItem() = default; |
| 68 |
| 69 protected: |
| 70 OptWorkItem() = default; |
| 71 }; |
| 72 |
57 class GlobalContext { | 73 class GlobalContext { |
58 GlobalContext() = delete; | 74 GlobalContext() = delete; |
59 GlobalContext(const GlobalContext &) = delete; | 75 GlobalContext(const GlobalContext &) = delete; |
60 GlobalContext &operator=(const GlobalContext &) = delete; | 76 GlobalContext &operator=(const GlobalContext &) = delete; |
61 | 77 |
62 /// CodeStats collects rudimentary statistics during translation. | 78 /// CodeStats collects rudimentary statistics during translation. |
63 class CodeStats { | 79 class CodeStats { |
64 CodeStats(const CodeStats &) = delete; | 80 CodeStats(const CodeStats &) = delete; |
65 CodeStats &operator=(const CodeStats &) = default; | 81 CodeStats &operator=(const CodeStats &) = default; |
66 #define CODESTATS_TABLE \ | 82 #define CODESTATS_TABLE \ |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 /// This is the first work item sequence number that the parser produces, and | 367 /// This is the first work item sequence number that the parser produces, and |
352 /// correspondingly the first sequence number that the emitter thread will | 368 /// correspondingly the first sequence number that the emitter thread will |
353 /// wait for. Start numbering at 1 to leave room for a sentinel, in case e.g. | 369 /// wait for. Start numbering at 1 to leave room for a sentinel, in case e.g. |
354 /// we wish to inject items with a special sequence number that may be | 370 /// we wish to inject items with a special sequence number that may be |
355 /// executed out of order. | 371 /// executed out of order. |
356 static constexpr uint32_t getFirstSequenceNumber() { return 1; } | 372 static constexpr uint32_t getFirstSequenceNumber() { return 1; } |
357 /// Adds a newly parsed and constructed function to the Cfg work queue. | 373 /// Adds a newly parsed and constructed function to the Cfg work queue. |
358 /// Notifies any idle workers that a new function is available for | 374 /// Notifies any idle workers that a new function is available for |
359 /// translating. May block if the work queue is too large, in order to control | 375 /// translating. May block if the work queue is too large, in order to control |
360 /// memory footprint. | 376 /// memory footprint. |
361 void optQueueBlockingPush(std::unique_ptr<Cfg> Func); | 377 void optQueueBlockingPush(std::unique_ptr<OptWorkItem> Item); |
362 /// Takes a Cfg from the work queue for translating. May block if the work | 378 /// Takes a Cfg from the work queue for translating. May block if the work |
363 /// queue is currently empty. Returns nullptr if there is no more work - the | 379 /// queue is currently empty. Returns nullptr if there is no more work - the |
364 /// queue is empty and either end() has been called or the Sequential flag was | 380 /// queue is empty and either end() has been called or the Sequential flag was |
365 /// set. | 381 /// set. |
366 std::unique_ptr<Cfg> optQueueBlockingPop(); | 382 std::unique_ptr<OptWorkItem> optQueueBlockingPop(); |
367 /// Notifies that no more work will be added to the work queue. | 383 /// Notifies that no more work will be added to the work queue. |
368 void optQueueNotifyEnd() { OptQ.notifyEnd(); } | 384 void optQueueNotifyEnd() { OptQ.notifyEnd(); } |
369 | 385 |
370 /// Emit file header for output file. | 386 /// Emit file header for output file. |
371 void emitFileHeader(); | 387 void emitFileHeader(); |
372 | 388 |
373 void lowerConstants(); | 389 void lowerConstants(); |
374 | 390 |
375 void lowerJumpTables(); | 391 void lowerJumpTables(); |
376 | 392 |
(...skipping 21 matching lines...) Expand all Loading... |
398 } | 414 } |
399 if (NumWorkers) { | 415 if (NumWorkers) { |
400 ThreadContext *WorkerTLS = new ThreadContext(); | 416 ThreadContext *WorkerTLS = new ThreadContext(); |
401 Timers->initInto(WorkerTLS->Timers); | 417 Timers->initInto(WorkerTLS->Timers); |
402 AllThreadContexts.push_back(WorkerTLS); | 418 AllThreadContexts.push_back(WorkerTLS); |
403 EmitterThreads.push_back( | 419 EmitterThreads.push_back( |
404 std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS)); | 420 std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS)); |
405 } | 421 } |
406 } | 422 } |
407 | 423 |
408 void waitForWorkerThreads() { | 424 void waitForWorkerThreads(); |
409 optQueueNotifyEnd(); | |
410 for (std::thread &Worker : TranslationThreads) { | |
411 Worker.join(); | |
412 } | |
413 TranslationThreads.clear(); | |
414 | |
415 // Only notify the emit queue to end after all the translation threads have | |
416 // ended. | |
417 emitQueueNotifyEnd(); | |
418 for (std::thread &Worker : EmitterThreads) { | |
419 Worker.join(); | |
420 } | |
421 EmitterThreads.clear(); | |
422 | |
423 if (BuildDefs::timers()) { | |
424 auto Timers = getTimers(); | |
425 for (ThreadContext *TLS : AllThreadContexts) | |
426 Timers->mergeFrom(TLS->Timers); | |
427 } | |
428 if (BuildDefs::dump()) { | |
429 // Do a separate loop over AllThreadContexts to avoid holding two locks | |
430 // at once. | |
431 auto Stats = getStatsCumulative(); | |
432 for (ThreadContext *TLS : AllThreadContexts) | |
433 Stats->add(TLS->StatsCumulative); | |
434 } | |
435 } | |
436 | 425 |
437 /// Translation thread startup routine. | 426 /// Translation thread startup routine. |
438 void translateFunctionsWrapper(ThreadContext *MyTLS) { | 427 void translateFunctionsWrapper(ThreadContext *MyTLS) { |
439 ICE_TLS_SET_FIELD(TLS, MyTLS); | 428 ICE_TLS_SET_FIELD(TLS, MyTLS); |
440 translateFunctions(); | 429 translateFunctions(); |
441 } | 430 } |
442 /// Translate functions from the Cfg queue until the queue is empty. | 431 /// Translate functions from the Cfg queue until the queue is empty. |
443 void translateFunctions(); | 432 void translateFunctions(); |
444 | 433 |
445 /// Emitter thread startup routine. | 434 /// Emitter thread startup routine. |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 TimerList Timers; | 527 TimerList Timers; |
539 | 528 |
540 ICE_CACHELINE_BOUNDARY; | 529 ICE_CACHELINE_BOUNDARY; |
541 /// StrLock is a global lock on the dump and emit output streams. | 530 /// StrLock is a global lock on the dump and emit output streams. |
542 using StrLockType = std::mutex; | 531 using StrLockType = std::mutex; |
543 StrLockType StrLock; | 532 StrLockType StrLock; |
544 Ostream *StrDump; /// Stream for dumping / diagnostics | 533 Ostream *StrDump; /// Stream for dumping / diagnostics |
545 Ostream *StrEmit; /// Stream for code emission | 534 Ostream *StrEmit; /// Stream for code emission |
546 Ostream *StrError; /// Stream for logging errors. | 535 Ostream *StrError; /// Stream for logging errors. |
547 | 536 |
| 537 // True if waitForWorkerThreads() has been called. |
| 538 std::atomic_bool WaitForWorkerThreadsCalled; |
| 539 |
548 ICE_CACHELINE_BOUNDARY; | 540 ICE_CACHELINE_BOUNDARY; |
549 | 541 |
550 Intrinsics IntrinsicsInfo; | 542 Intrinsics IntrinsicsInfo; |
551 // TODO(jpp): move to EmitterContext. | 543 // TODO(jpp): move to EmitterContext. |
552 std::unique_ptr<ELFObjectWriter> ObjectWriter; | 544 std::unique_ptr<ELFObjectWriter> ObjectWriter; |
553 BoundedProducerConsumerQueue<Cfg> OptQ; | 545 static constexpr size_t MaxOptQSize = 1 << 16; |
| 546 BoundedProducerConsumerQueue<OptWorkItem, MaxOptQSize> OptQ; |
554 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ; | 547 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ; |
555 // DataLowering is only ever used by a single thread at a time (either in | 548 // DataLowering is only ever used by a single thread at a time (either in |
556 // emitItems(), or in IceCompiler::run before the compilation is over.) | 549 // emitItems(), or in IceCompiler::run before the compilation is over.) |
557 // TODO(jpp): move to EmitterContext. | 550 // TODO(jpp): move to EmitterContext. |
558 std::unique_ptr<TargetDataLowering> DataLowering; | 551 std::unique_ptr<TargetDataLowering> DataLowering; |
559 /// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true" | 552 /// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true" |
560 /// program global variables) until the first code WorkItem is seen. | 553 /// program global variables) until the first code WorkItem is seen. |
561 // TODO(jpp): move to EmitterContext. | 554 // TODO(jpp): move to EmitterContext. |
562 bool HasSeenCode = false; | 555 bool HasSeenCode = false; |
563 // TODO(jpp): move to EmitterContext. | 556 // TODO(jpp): move to EmitterContext. |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
684 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } | 677 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } |
685 ~OstreamLocker() { Ctx->unlockStr(); } | 678 ~OstreamLocker() { Ctx->unlockStr(); } |
686 | 679 |
687 private: | 680 private: |
688 GlobalContext *const Ctx; | 681 GlobalContext *const Ctx; |
689 }; | 682 }; |
690 | 683 |
691 } // end of namespace Ice | 684 } // end of namespace Ice |
692 | 685 |
693 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H | 686 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H |
OLD | NEW |