1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceThreading.h - Threading functions ---------*- C++ -*-===// 2*03ce13f7SAndroid Build Coastguard Worker // 3*03ce13f7SAndroid Build Coastguard Worker // The Subzero Code Generator 4*03ce13f7SAndroid Build Coastguard Worker // 5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source 6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details. 7*03ce13f7SAndroid Build Coastguard Worker // 8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 9*03ce13f7SAndroid Build Coastguard Worker /// 10*03ce13f7SAndroid Build Coastguard Worker /// \file 11*03ce13f7SAndroid Build Coastguard Worker /// \brief Declares threading-related functions. 12*03ce13f7SAndroid Build Coastguard Worker /// 13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 14*03ce13f7SAndroid Build Coastguard Worker 15*03ce13f7SAndroid Build Coastguard Worker #ifndef SUBZERO_SRC_ICETHREADING_H 16*03ce13f7SAndroid Build Coastguard Worker #define SUBZERO_SRC_ICETHREADING_H 17*03ce13f7SAndroid Build Coastguard Worker 18*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h" 19*03ce13f7SAndroid Build Coastguard Worker 20*03ce13f7SAndroid Build Coastguard Worker #include <condition_variable> 21*03ce13f7SAndroid Build Coastguard Worker #include <memory> 22*03ce13f7SAndroid Build Coastguard Worker #include <mutex> 23*03ce13f7SAndroid Build Coastguard Worker #include <utility> 24*03ce13f7SAndroid Build Coastguard Worker 25*03ce13f7SAndroid Build Coastguard Worker namespace Ice { 26*03ce13f7SAndroid Build Coastguard Worker 27*03ce13f7SAndroid Build Coastguard Worker /// BoundedProducerConsumerQueue is a work queue that allows multiple producers 28*03ce13f7SAndroid Build Coastguard Worker /// and multiple consumers. A producer adds entries using blockingPush(), and 29*03ce13f7SAndroid Build Coastguard Worker /// may block if the queue is "full". A producer uses notifyEnd() to indicate 30*03ce13f7SAndroid Build Coastguard Worker /// that no more entries will be added. A consumer removes an item using 31*03ce13f7SAndroid Build Coastguard Worker /// blockingPop(), which will return nullptr if notifyEnd() has been called and 32*03ce13f7SAndroid Build Coastguard Worker /// the queue is empty (it never returns nullptr if the queue contained any 33*03ce13f7SAndroid Build Coastguard Worker /// items). 34*03ce13f7SAndroid Build Coastguard Worker /// 35*03ce13f7SAndroid Build Coastguard Worker /// The MaxSize ctor arg controls the maximum size the queue can grow to 36*03ce13f7SAndroid Build Coastguard Worker /// (subject to a hard limit of MaxStaticSize-1). The Sequential arg indicates 37*03ce13f7SAndroid Build Coastguard Worker /// purely sequential execution in which the single thread should never wait(). 38*03ce13f7SAndroid Build Coastguard Worker /// 39*03ce13f7SAndroid Build Coastguard Worker /// Two condition variables are used in the implementation. GrewOrEnded signals 40*03ce13f7SAndroid Build Coastguard Worker /// a waiting worker that a producer has changed the state of the queue. Shrunk 41*03ce13f7SAndroid Build Coastguard Worker /// signals a blocked producer that a consumer has changed the state of the 42*03ce13f7SAndroid Build Coastguard Worker /// queue. 43*03ce13f7SAndroid Build Coastguard Worker /// 44*03ce13f7SAndroid Build Coastguard Worker /// The methods begin with Sequential-specific code to be most clear. The lock 45*03ce13f7SAndroid Build Coastguard Worker /// and condition variables are not used in the Sequential case. 46*03ce13f7SAndroid Build Coastguard Worker /// 47*03ce13f7SAndroid Build Coastguard Worker /// Internally, the queue is implemented as a circular array of size 48*03ce13f7SAndroid Build Coastguard Worker /// MaxStaticSize, where the queue boundaries are denoted by the Front and Back 49*03ce13f7SAndroid Build Coastguard Worker /// fields. Front==Back indicates an empty queue. 50*03ce13f7SAndroid Build Coastguard Worker template <typename T, size_t MaxStaticSize = 128> 51*03ce13f7SAndroid Build Coastguard Worker class BoundedProducerConsumerQueue { 52*03ce13f7SAndroid Build Coastguard Worker BoundedProducerConsumerQueue() = delete; 53*03ce13f7SAndroid Build Coastguard Worker BoundedProducerConsumerQueue(const BoundedProducerConsumerQueue &) = delete; 54*03ce13f7SAndroid Build Coastguard Worker BoundedProducerConsumerQueue & 55*03ce13f7SAndroid Build Coastguard Worker operator=(const BoundedProducerConsumerQueue &) = delete; 56*03ce13f7SAndroid Build Coastguard Worker 57*03ce13f7SAndroid Build Coastguard Worker public: 58*03ce13f7SAndroid Build Coastguard Worker BoundedProducerConsumerQueue(bool Sequential, size_t MaxSize = MaxStaticSize) MaxSize(std::min (MaxSize,MaxStaticSize))59*03ce13f7SAndroid Build Coastguard Worker : MaxSize(std::min(MaxSize, MaxStaticSize)), Sequential(Sequential) {} blockingPush(std::unique_ptr<T> Item)60*03ce13f7SAndroid Build Coastguard Worker void blockingPush(std::unique_ptr<T> Item) { 61*03ce13f7SAndroid Build Coastguard Worker { 62*03ce13f7SAndroid Build Coastguard Worker std::unique_lock<GlobalLockType> L(Lock); 63*03ce13f7SAndroid Build Coastguard Worker // If the work queue is already "full", wait for a consumer to grab an 64*03ce13f7SAndroid Build Coastguard Worker // element and shrink the queue. 65*03ce13f7SAndroid Build Coastguard Worker Shrunk.wait(L, [this] { return size() < MaxSize || Sequential; }); 66*03ce13f7SAndroid Build Coastguard Worker push(std::move(Item)); 67*03ce13f7SAndroid Build Coastguard Worker } 68*03ce13f7SAndroid Build Coastguard Worker GrewOrEnded.notify_one(); 69*03ce13f7SAndroid Build Coastguard Worker } 70*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<T> blockingPop(size_t NotifyWhenDownToSize = MaxStaticSize) { 71*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<T> Item; 72*03ce13f7SAndroid Build Coastguard Worker bool ShouldNotifyProducer = false; 73*03ce13f7SAndroid Build Coastguard Worker { 74*03ce13f7SAndroid Build Coastguard Worker std::unique_lock<GlobalLockType> L(Lock); 75*03ce13f7SAndroid Build Coastguard Worker GrewOrEnded.wait(L, [this] { return IsEnded || !empty() || Sequential; }); 76*03ce13f7SAndroid Build Coastguard Worker if (!empty()) { 77*03ce13f7SAndroid Build Coastguard Worker Item = pop(); 78*03ce13f7SAndroid Build Coastguard Worker ShouldNotifyProducer = (size() < NotifyWhenDownToSize) && !IsEnded; 79*03ce13f7SAndroid Build Coastguard Worker } 80*03ce13f7SAndroid Build Coastguard Worker } 81*03ce13f7SAndroid Build Coastguard Worker if (ShouldNotifyProducer) 82*03ce13f7SAndroid Build Coastguard Worker Shrunk.notify_one(); 83*03ce13f7SAndroid Build Coastguard Worker return Item; 84*03ce13f7SAndroid Build Coastguard Worker } notifyEnd()85*03ce13f7SAndroid Build Coastguard Worker void notifyEnd() { 86*03ce13f7SAndroid Build Coastguard Worker { 87*03ce13f7SAndroid Build Coastguard Worker std::lock_guard<GlobalLockType> L(Lock); 88*03ce13f7SAndroid Build Coastguard Worker IsEnded = true; 89*03ce13f7SAndroid Build Coastguard Worker } 90*03ce13f7SAndroid Build Coastguard Worker GrewOrEnded.notify_all(); 91*03ce13f7SAndroid Build Coastguard Worker } 92*03ce13f7SAndroid Build Coastguard Worker 93*03ce13f7SAndroid Build Coastguard Worker private: 94*03ce13f7SAndroid Build Coastguard Worker const static size_t MaxStaticSizeMask = MaxStaticSize - 1; 95*03ce13f7SAndroid Build Coastguard Worker static_assert(!(MaxStaticSize & (MaxStaticSize - 1)), 96*03ce13f7SAndroid Build Coastguard Worker "MaxStaticSize must be a power of 2"); 97*03ce13f7SAndroid Build Coastguard Worker 98*03ce13f7SAndroid Build Coastguard Worker ICE_CACHELINE_BOUNDARY; 99*03ce13f7SAndroid Build Coastguard Worker /// WorkItems and Lock are read/written by all. 100*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<T> WorkItems[MaxStaticSize]; 101*03ce13f7SAndroid Build Coastguard Worker ICE_CACHELINE_BOUNDARY; 102*03ce13f7SAndroid Build Coastguard Worker /// Lock guards access to WorkItems, Front, Back, and IsEnded. 103*03ce13f7SAndroid Build Coastguard Worker GlobalLockType Lock; 104*03ce13f7SAndroid Build Coastguard Worker 105*03ce13f7SAndroid Build Coastguard Worker ICE_CACHELINE_BOUNDARY; 106*03ce13f7SAndroid Build Coastguard Worker /// GrewOrEnded is written by the producers and read by the consumers. It is 107*03ce13f7SAndroid Build Coastguard Worker /// notified (by the producer) when something is added to the queue, in case 108*03ce13f7SAndroid Build Coastguard Worker /// consumers are waiting for a non-empty queue. 109*03ce13f7SAndroid Build Coastguard Worker std::condition_variable GrewOrEnded; 110*03ce13f7SAndroid Build Coastguard Worker /// Back is the index into WorkItems[] of where the next element will be 111*03ce13f7SAndroid Build Coastguard Worker /// pushed. (More precisely, Back&MaxStaticSize is the index.) It is written 112*03ce13f7SAndroid Build Coastguard Worker /// by the producers, and read by all via size() and empty(). 113*03ce13f7SAndroid Build Coastguard Worker size_t Back = 0; 114*03ce13f7SAndroid Build Coastguard Worker 115*03ce13f7SAndroid Build Coastguard Worker ICE_CACHELINE_BOUNDARY; 116*03ce13f7SAndroid Build Coastguard Worker /// Shrunk is notified (by the consumer) when something is removed from the 117*03ce13f7SAndroid Build Coastguard Worker /// queue, in case a producer is waiting for the queue to drop below maximum 118*03ce13f7SAndroid Build Coastguard Worker /// capacity. It is written by the consumers and read by the producers. 119*03ce13f7SAndroid Build Coastguard Worker std::condition_variable Shrunk; 120*03ce13f7SAndroid Build Coastguard Worker /// Front is the index into WorkItems[] of the oldest element, i.e. the next 121*03ce13f7SAndroid Build Coastguard Worker /// to be popped. (More precisely Front&MaxStaticSize is the index.) It is 122*03ce13f7SAndroid Build Coastguard Worker /// written by the consumers, and read by all via size() and empty(). 123*03ce13f7SAndroid Build Coastguard Worker size_t Front = 0; 124*03ce13f7SAndroid Build Coastguard Worker 125*03ce13f7SAndroid Build Coastguard Worker ICE_CACHELINE_BOUNDARY; 126*03ce13f7SAndroid Build Coastguard Worker 127*03ce13f7SAndroid Build Coastguard Worker /// MaxSize and Sequential are read by all and written by none. 128*03ce13f7SAndroid Build Coastguard Worker const size_t MaxSize; 129*03ce13f7SAndroid Build Coastguard Worker const bool Sequential; 130*03ce13f7SAndroid Build Coastguard Worker /// IsEnded is read by the consumers, and only written once by the producer. 131*03ce13f7SAndroid Build Coastguard Worker bool IsEnded = false; 132*03ce13f7SAndroid Build Coastguard Worker 133*03ce13f7SAndroid Build Coastguard Worker /// The lock must be held when the following methods are called. empty()134*03ce13f7SAndroid Build Coastguard Worker bool empty() const { return Front == Back; } size()135*03ce13f7SAndroid Build Coastguard Worker size_t size() const { return Back - Front; } push(std::unique_ptr<T> Item)136*03ce13f7SAndroid Build Coastguard Worker void push(std::unique_ptr<T> Item) { 137*03ce13f7SAndroid Build Coastguard Worker WorkItems[Back++ & MaxStaticSizeMask] = std::move(Item); 138*03ce13f7SAndroid Build Coastguard Worker assert(size() <= MaxStaticSize); 139*03ce13f7SAndroid Build Coastguard Worker } pop()140*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<T> pop() { 141*03ce13f7SAndroid Build Coastguard Worker assert(!empty()); 142*03ce13f7SAndroid Build Coastguard Worker return std::move(WorkItems[Front++ & MaxStaticSizeMask]); 143*03ce13f7SAndroid Build Coastguard Worker } 144*03ce13f7SAndroid Build Coastguard Worker }; 145*03ce13f7SAndroid Build Coastguard Worker 146*03ce13f7SAndroid Build Coastguard Worker /// EmitterWorkItem is a simple wrapper around a pointer that represents a work 147*03ce13f7SAndroid Build Coastguard Worker /// item to be emitted, i.e. a function or a set of global declarations and 148*03ce13f7SAndroid Build Coastguard Worker /// initializers, and it includes a sequence number so that work items can be 149*03ce13f7SAndroid Build Coastguard Worker /// emitted in a particular order for deterministic output. It acts like an 150*03ce13f7SAndroid Build Coastguard Worker /// interface class, but instead of making the classes of interest inherit from 151*03ce13f7SAndroid Build Coastguard Worker /// EmitterWorkItem, it wraps pointers to these classes. Some space is wasted 152*03ce13f7SAndroid Build Coastguard Worker /// compared to storing the pointers in a union, but not too much due to the 153*03ce13f7SAndroid Build Coastguard Worker /// work granularity. 154*03ce13f7SAndroid Build Coastguard Worker class EmitterWorkItem { 155*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem() = delete; 156*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem(const EmitterWorkItem &) = delete; 157*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem &operator=(const EmitterWorkItem &) = delete; 158*03ce13f7SAndroid Build Coastguard Worker 159*03ce13f7SAndroid Build Coastguard Worker public: 160*03ce13f7SAndroid Build Coastguard Worker /// ItemKind can be one of the following: 161*03ce13f7SAndroid Build Coastguard Worker /// 162*03ce13f7SAndroid Build Coastguard Worker /// WI_Nop: No actual work. This is a placeholder to maintain sequence numbers 163*03ce13f7SAndroid Build Coastguard Worker /// in case there is a translation error. 164*03ce13f7SAndroid Build Coastguard Worker /// 165*03ce13f7SAndroid Build Coastguard Worker /// WI_GlobalInits: A list of global declarations and initializers. 166*03ce13f7SAndroid Build Coastguard Worker /// 167*03ce13f7SAndroid Build Coastguard Worker /// WI_Asm: A function that has already had emitIAS() called on it. The work 168*03ce13f7SAndroid Build Coastguard Worker /// is transferred via the Assembler buffer, and the originating Cfg has been 169*03ce13f7SAndroid Build Coastguard Worker /// deleted (to recover lots of memory). 170*03ce13f7SAndroid Build Coastguard Worker /// 171*03ce13f7SAndroid Build Coastguard Worker /// WI_Cfg: A Cfg that has not yet had emit() or emitIAS() called on it. This 172*03ce13f7SAndroid Build Coastguard Worker /// is only used as a debugging configuration when we want to emit "readable" 173*03ce13f7SAndroid Build Coastguard Worker /// assembly code, possibly annotated with liveness and other information only 174*03ce13f7SAndroid Build Coastguard Worker /// available in the Cfg and not in the Assembler buffer. 175*03ce13f7SAndroid Build Coastguard Worker enum ItemKind { WI_Nop, WI_GlobalInits, WI_Asm, WI_Cfg }; 176*03ce13f7SAndroid Build Coastguard Worker /// Constructor for a WI_Nop work item. 177*03ce13f7SAndroid Build Coastguard Worker explicit EmitterWorkItem(uint32_t Seq); 178*03ce13f7SAndroid Build Coastguard Worker /// Constructor for a WI_GlobalInits work item. 179*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem(uint32_t Seq, std::unique_ptr<VariableDeclarationList> D); 180*03ce13f7SAndroid Build Coastguard Worker /// Constructor for a WI_Asm work item. 181*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem(uint32_t Seq, std::unique_ptr<Assembler> A); 182*03ce13f7SAndroid Build Coastguard Worker /// Constructor for a WI_Cfg work item. 183*03ce13f7SAndroid Build Coastguard Worker EmitterWorkItem(uint32_t Seq, std::unique_ptr<Cfg> F); getSequenceNumber()184*03ce13f7SAndroid Build Coastguard Worker uint32_t getSequenceNumber() const { return Sequence; } getKind()185*03ce13f7SAndroid Build Coastguard Worker ItemKind getKind() const { return Kind; } 186*03ce13f7SAndroid Build Coastguard Worker void setGlobalInits(std::unique_ptr<VariableDeclarationList> GloblInits); 187*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<VariableDeclarationList> getGlobalInits(); 188*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<Assembler> getAsm(); 189*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<Cfg> getCfg(); 190*03ce13f7SAndroid Build Coastguard Worker 191*03ce13f7SAndroid Build Coastguard Worker private: 192*03ce13f7SAndroid Build Coastguard Worker const uint32_t Sequence; 193*03ce13f7SAndroid Build Coastguard Worker const ItemKind Kind; 194*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<VariableDeclarationList> GlobalInits; 195*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<Assembler> Function; 196*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<Cfg> RawFunc; 197*03ce13f7SAndroid Build Coastguard Worker }; 198*03ce13f7SAndroid Build Coastguard Worker 199*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice 200*03ce13f7SAndroid Build Coastguard Worker 201*03ce13f7SAndroid Build Coastguard Worker #endif // SUBZERO_SRC_ICETHREADING_H 202