| 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 // This file declares aspects of the compilation that persist across | 10 // This file declares aspects of the compilation that persist across |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 #include <type_traits> | 31 #include <type_traits> |
| 32 #include <vector> | 32 #include <vector> |
| 33 | 33 |
| 34 namespace Ice { | 34 namespace Ice { |
| 35 | 35 |
| 36 class ClFlags; | 36 class ClFlags; |
| 37 class ConstantPool; | 37 class ConstantPool; |
| 38 class EmitterWorkItem; | 38 class EmitterWorkItem; |
| 39 class FuncSigType; | 39 class FuncSigType; |
| 40 | 40 |
| 41 // LockedPtr is a way to provide automatically locked access to some object. | 41 /// LockedPtr is a way to provide automatically locked access to some object. |
| 42 template <typename T> class LockedPtr { | 42 template <typename T> class LockedPtr { |
| 43 LockedPtr() = delete; | 43 LockedPtr() = delete; |
| 44 LockedPtr(const LockedPtr &) = delete; | 44 LockedPtr(const LockedPtr &) = delete; |
| 45 LockedPtr &operator=(const LockedPtr &) = delete; | 45 LockedPtr &operator=(const LockedPtr &) = delete; |
| 46 | 46 |
| 47 public: | 47 public: |
| 48 LockedPtr(T *Value, GlobalLockType *Lock) : Value(Value), Lock(Lock) { | 48 LockedPtr(T *Value, GlobalLockType *Lock) : Value(Value), Lock(Lock) { |
| 49 Lock->lock(); | 49 Lock->lock(); |
| 50 } | 50 } |
| 51 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) { | 51 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) { |
| 52 Other.Value = nullptr; | 52 Other.Value = nullptr; |
| 53 Other.Lock = nullptr; | 53 Other.Lock = nullptr; |
| 54 } | 54 } |
| 55 ~LockedPtr() { Lock->unlock(); } | 55 ~LockedPtr() { Lock->unlock(); } |
| 56 T *operator->() const { return Value; } | 56 T *operator->() const { return Value; } |
| 57 | 57 |
| 58 private: | 58 private: |
| 59 T *Value; | 59 T *Value; |
| 60 GlobalLockType *Lock; | 60 GlobalLockType *Lock; |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 class GlobalContext { | 63 class GlobalContext { |
| 64 GlobalContext() = delete; | 64 GlobalContext() = delete; |
| 65 GlobalContext(const GlobalContext &) = delete; | 65 GlobalContext(const GlobalContext &) = delete; |
| 66 GlobalContext &operator=(const GlobalContext &) = delete; | 66 GlobalContext &operator=(const GlobalContext &) = delete; |
| 67 | 67 |
| 68 // CodeStats collects rudimentary statistics during translation. | 68 /// CodeStats collects rudimentary statistics during translation. |
| 69 class CodeStats { | 69 class CodeStats { |
| 70 CodeStats(const CodeStats &) = delete; | 70 CodeStats(const CodeStats &) = delete; |
| 71 CodeStats &operator=(const CodeStats &) = default; | 71 CodeStats &operator=(const CodeStats &) = default; |
| 72 #define CODESTATS_TABLE \ | 72 #define CODESTATS_TABLE \ |
| 73 /* dump string, enum value */ \ | 73 /* dump string, enum value */ \ |
| 74 X("Inst Count ", InstCount) \ | 74 X("Inst Count ", InstCount) \ |
| 75 X("Regs Saved ", RegsSaved) \ | 75 X("Regs Saved ", RegsSaved) \ |
| 76 X("Frame Bytes ", FrameByte) \ | 76 X("Frame Bytes ", FrameByte) \ |
| 77 X("Spills ", NumSpills) \ | 77 X("Spills ", NumSpills) \ |
| 78 X("Fills ", NumFills) \ | 78 X("Fills ", NumFills) \ |
| (...skipping 16 matching lines...) Expand all Loading... |
| 95 void add(const CodeStats &Other) { | 95 void add(const CodeStats &Other) { |
| 96 for (uint32_t i = 0; i < Stats.size(); ++i) | 96 for (uint32_t i = 0; i < Stats.size(); ++i) |
| 97 Stats[i] += Other.Stats[i]; | 97 Stats[i] += Other.Stats[i]; |
| 98 } | 98 } |
| 99 void dump(const IceString &Name, Ostream &Str); | 99 void dump(const IceString &Name, Ostream &Str); |
| 100 | 100 |
| 101 private: | 101 private: |
| 102 std::array<uint32_t, CS_NUM> Stats; | 102 std::array<uint32_t, CS_NUM> Stats; |
| 103 }; | 103 }; |
| 104 | 104 |
| 105 // TimerList is a vector of TimerStack objects, with extra methods | 105 /// TimerList is a vector of TimerStack objects, with extra methods |
| 106 // to initialize and merge these vectors. | 106 /// to initialize and merge these vectors. |
| 107 class TimerList : public std::vector<TimerStack> { | 107 class TimerList : public std::vector<TimerStack> { |
| 108 TimerList(const TimerList &) = delete; | 108 TimerList(const TimerList &) = delete; |
| 109 TimerList &operator=(const TimerList &) = delete; | 109 TimerList &operator=(const TimerList &) = delete; |
| 110 | 110 |
| 111 public: | 111 public: |
| 112 TimerList() = default; | 112 TimerList() = default; |
| 113 // initInto() initializes a target list of timers based on the | 113 /// initInto() initializes a target list of timers based on the |
| 114 // current list. In particular, it creates the same number of | 114 /// current list. In particular, it creates the same number of |
| 115 // timers, in the same order, with the same names, but initially | 115 /// timers, in the same order, with the same names, but initially |
| 116 // empty of timing data. | 116 /// empty of timing data. |
| 117 void initInto(TimerList &Dest) const { | 117 void initInto(TimerList &Dest) const { |
| 118 if (!BuildDefs::dump()) | 118 if (!BuildDefs::dump()) |
| 119 return; | 119 return; |
| 120 Dest.clear(); | 120 Dest.clear(); |
| 121 for (const TimerStack &Stack : *this) { | 121 for (const TimerStack &Stack : *this) { |
| 122 Dest.push_back(TimerStack(Stack.getName())); | 122 Dest.push_back(TimerStack(Stack.getName())); |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 void mergeFrom(TimerList &Src) { | 125 void mergeFrom(TimerList &Src) { |
| 126 if (!BuildDefs::dump()) | 126 if (!BuildDefs::dump()) |
| 127 return; | 127 return; |
| 128 assert(size() == Src.size()); | 128 assert(size() == Src.size()); |
| 129 size_type i = 0; | 129 size_type i = 0; |
| 130 for (TimerStack &Stack : *this) { | 130 for (TimerStack &Stack : *this) { |
| 131 assert(Stack.getName() == Src[i].getName()); | 131 assert(Stack.getName() == Src[i].getName()); |
| 132 Stack.mergeFrom(Src[i]); | 132 Stack.mergeFrom(Src[i]); |
| 133 ++i; | 133 ++i; |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 }; | 136 }; |
| 137 | 137 |
| 138 // ThreadContext contains thread-local data. This data can be | 138 /// ThreadContext contains thread-local data. This data can be |
| 139 // combined/reduced as needed after all threads complete. | 139 /// combined/reduced as needed after all threads complete. |
| 140 class ThreadContext { | 140 class ThreadContext { |
| 141 ThreadContext(const ThreadContext &) = delete; | 141 ThreadContext(const ThreadContext &) = delete; |
| 142 ThreadContext &operator=(const ThreadContext &) = delete; | 142 ThreadContext &operator=(const ThreadContext &) = delete; |
| 143 | 143 |
| 144 public: | 144 public: |
| 145 ThreadContext() = default; | 145 ThreadContext() = default; |
| 146 CodeStats StatsFunction; | 146 CodeStats StatsFunction; |
| 147 CodeStats StatsCumulative; | 147 CodeStats StatsCumulative; |
| 148 TimerList Timers; | 148 TimerList Timers; |
| 149 }; | 149 }; |
| 150 | 150 |
| 151 public: | 151 public: |
| 152 // The dump stream is a log stream while emit is the stream code | 152 /// The dump stream is a log stream while emit is the stream code |
| 153 // is emitted to. The error stream is strictly for logging errors. | 153 /// is emitted to. The error stream is strictly for logging errors. |
| 154 GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError, | 154 GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError, |
| 155 ELFStreamer *ELFStreamer, const ClFlags &Flags); | 155 ELFStreamer *ELFStreamer, const ClFlags &Flags); |
| 156 ~GlobalContext(); | 156 ~GlobalContext(); |
| 157 | 157 |
| 158 // | 158 /// |
| 159 // The dump, error, and emit streams need to be used by only one | 159 /// The dump, error, and emit streams need to be used by only one |
| 160 // thread at a time. This is done by exclusively reserving the | 160 /// thread at a time. This is done by exclusively reserving the |
| 161 // streams via lockStr() and unlockStr(). The OstreamLocker class | 161 /// streams via lockStr() and unlockStr(). The OstreamLocker class |
| 162 // can be used to conveniently manage this. | 162 /// can be used to conveniently manage this. |
| 163 // | 163 /// |
| 164 // The model is that a thread grabs the stream lock, then does an | 164 /// The model is that a thread grabs the stream lock, then does an |
| 165 // arbitrary amount of work during which far-away callees may grab | 165 /// arbitrary amount of work during which far-away callees may grab |
| 166 // the stream and do something with it, and finally the thread | 166 /// the stream and do something with it, and finally the thread |
| 167 // releases the stream lock. This allows large chunks of output to | 167 /// releases the stream lock. This allows large chunks of output to |
| 168 // be dumped or emitted without risking interleaving from multiple | 168 /// be dumped or emitted without risking interleaving from multiple |
| 169 // threads. | 169 /// threads. |
| 170 void lockStr() { StrLock.lock(); } | 170 void lockStr() { StrLock.lock(); } |
| 171 void unlockStr() { StrLock.unlock(); } | 171 void unlockStr() { StrLock.unlock(); } |
| 172 Ostream &getStrDump() { return *StrDump; } | 172 Ostream &getStrDump() { return *StrDump; } |
| 173 Ostream &getStrError() { return *StrError; } | 173 Ostream &getStrError() { return *StrError; } |
| 174 Ostream &getStrEmit() { return *StrEmit; } | 174 Ostream &getStrEmit() { return *StrEmit; } |
| 175 | 175 |
| 176 LockedPtr<ErrorCode> getErrorStatus() { | 176 LockedPtr<ErrorCode> getErrorStatus() { |
| 177 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock); | 177 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock); |
| 178 } | 178 } |
| 179 | 179 |
| 180 // When emitting assembly, we allow a string to be prepended to | 180 /// When emitting assembly, we allow a string to be prepended to |
| 181 // names of translated functions. This makes it easier to create an | 181 /// names of translated functions. This makes it easier to create an |
| 182 // execution test against a reference translator like llc, with both | 182 /// execution test against a reference translator like llc, with both |
| 183 // translators using the same bitcode as input. | 183 /// translators using the same bitcode as input. |
| 184 IceString mangleName(const IceString &Name) const; | 184 IceString mangleName(const IceString &Name) const; |
| 185 | 185 |
| 186 // Manage Constants. | 186 // Manage Constants. |
| 187 // getConstant*() functions are not const because they might add | 187 // getConstant*() functions are not const because they might add |
| 188 // something to the constant pool. | 188 // something to the constant pool. |
| 189 Constant *getConstantInt(Type Ty, int64_t Value); | 189 Constant *getConstantInt(Type Ty, int64_t Value); |
| 190 Constant *getConstantInt1(int8_t ConstantInt1); | 190 Constant *getConstantInt1(int8_t ConstantInt1); |
| 191 Constant *getConstantInt8(int8_t ConstantInt8); | 191 Constant *getConstantInt8(int8_t ConstantInt8); |
| 192 Constant *getConstantInt16(int16_t ConstantInt16); | 192 Constant *getConstantInt16(int16_t ConstantInt16); |
| 193 Constant *getConstantInt32(int32_t ConstantInt32); | 193 Constant *getConstantInt32(int32_t ConstantInt32); |
| 194 Constant *getConstantInt64(int64_t ConstantInt64); | 194 Constant *getConstantInt64(int64_t ConstantInt64); |
| 195 Constant *getConstantFloat(float Value); | 195 Constant *getConstantFloat(float Value); |
| 196 Constant *getConstantDouble(double Value); | 196 Constant *getConstantDouble(double Value); |
| 197 // Returns a symbolic constant. | 197 /// Returns a symbolic constant. |
| 198 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name, | 198 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name, |
| 199 bool SuppressMangling); | 199 bool SuppressMangling); |
| 200 Constant *getConstantExternSym(const IceString &Name); | 200 Constant *getConstantExternSym(const IceString &Name); |
| 201 // Returns an undef. | 201 /// Returns an undef. |
| 202 Constant *getConstantUndef(Type Ty); | 202 Constant *getConstantUndef(Type Ty); |
| 203 // Returns a zero value. | 203 /// Returns a zero value. |
| 204 Constant *getConstantZero(Type Ty); | 204 Constant *getConstantZero(Type Ty); |
| 205 // getConstantPool() returns a copy of the constant pool for | 205 /// getConstantPool() returns a copy of the constant pool for |
| 206 // constants of a given type. | 206 /// constants of a given type. |
| 207 ConstantList getConstantPool(Type Ty); | 207 ConstantList getConstantPool(Type Ty); |
| 208 // Returns a copy of the list of external symbols. | 208 /// Returns a copy of the list of external symbols. |
| 209 ConstantList getConstantExternSyms(); | 209 ConstantList getConstantExternSyms(); |
| 210 | 210 |
| 211 const ClFlags &getFlags() const { return Flags; } | 211 const ClFlags &getFlags() const { return Flags; } |
| 212 | 212 |
| 213 bool isIRGenerationDisabled() const { | 213 bool isIRGenerationDisabled() const { |
| 214 return getFlags().getDisableIRGeneration(); | 214 return getFlags().getDisableIRGeneration(); |
| 215 } | 215 } |
| 216 | 216 |
| 217 // Allocate data of type T using the global allocator. We allow entities | 217 /// Allocate data of type T using the global allocator. We allow entities |
| 218 // allocated from this global allocator to be either trivially or | 218 /// allocated from this global allocator to be either trivially or |
| 219 // non-trivially destructible. We optimize the case when T is trivially | 219 /// non-trivially destructible. We optimize the case when T is trivially |
| 220 // destructible by not registering a destructor. Destructors will be invoked | 220 /// destructible by not registering a destructor. Destructors will be invoked |
| 221 // during GlobalContext destruction in the reverse object creation order. | 221 /// during GlobalContext destruction in the reverse object creation order. |
| 222 template <typename T> | 222 template <typename T> |
| 223 typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type * | 223 typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type * |
| 224 allocate() { | 224 allocate() { |
| 225 return getAllocator()->Allocate<T>(); | 225 return getAllocator()->Allocate<T>(); |
| 226 } | 226 } |
| 227 | 227 |
| 228 template <typename T> | 228 template <typename T> |
| 229 typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type * | 229 typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type * |
| 230 allocate() { | 230 allocate() { |
| 231 T *Ret = getAllocator()->Allocate<T>(); | 231 T *Ret = getAllocator()->Allocate<T>(); |
| 232 getDestructors()->emplace_back([Ret]() { Ret->~T(); }); | 232 getDestructors()->emplace_back([Ret]() { Ret->~T(); }); |
| 233 return Ret; | 233 return Ret; |
| 234 } | 234 } |
| 235 | 235 |
| 236 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; } | 236 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; } |
| 237 | 237 |
| 238 // TODO(wala,stichnot): Make the RNG play nicely with multithreaded | 238 // TODO(wala,stichnot): Make the RNG play nicely with multithreaded |
| 239 // translation. | 239 // translation. |
| 240 RandomNumberGenerator &getRNG() { return RNG; } | 240 RandomNumberGenerator &getRNG() { return RNG; } |
| 241 | 241 |
| 242 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); } | 242 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); } |
| 243 | 243 |
| 244 // Reset stats at the beginning of a function. | 244 /// Reset stats at the beginning of a function. |
| 245 void resetStats() { | 245 void resetStats() { |
| 246 if (BuildDefs::dump()) | 246 if (BuildDefs::dump()) |
| 247 ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset(); | 247 ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset(); |
| 248 } | 248 } |
| 249 void dumpStats(const IceString &Name, bool Final = false); | 249 void dumpStats(const IceString &Name, bool Final = false); |
| 250 void statsUpdateEmitted(uint32_t InstCount) { | 250 void statsUpdateEmitted(uint32_t InstCount) { |
| 251 if (!getFlags().getDumpStats()) | 251 if (!getFlags().getDumpStats()) |
| 252 return; | 252 return; |
| 253 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); | 253 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); |
| 254 Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount); | 254 Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 276 Tls->StatsCumulative.update(CodeStats::CS_NumSpills); | 276 Tls->StatsCumulative.update(CodeStats::CS_NumSpills); |
| 277 } | 277 } |
| 278 void statsUpdateFills() { | 278 void statsUpdateFills() { |
| 279 if (!getFlags().getDumpStats()) | 279 if (!getFlags().getDumpStats()) |
| 280 return; | 280 return; |
| 281 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); | 281 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); |
| 282 Tls->StatsFunction.update(CodeStats::CS_NumFills); | 282 Tls->StatsFunction.update(CodeStats::CS_NumFills); |
| 283 Tls->StatsCumulative.update(CodeStats::CS_NumFills); | 283 Tls->StatsCumulative.update(CodeStats::CS_NumFills); |
| 284 } | 284 } |
| 285 | 285 |
| 286 // Number of Randomized or Pooled Immediates | 286 /// Number of Randomized or Pooled Immediates |
| 287 void statsUpdateRPImms() { | 287 void statsUpdateRPImms() { |
| 288 if (!getFlags().getDumpStats()) | 288 if (!getFlags().getDumpStats()) |
| 289 return; | 289 return; |
| 290 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); | 290 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); |
| 291 Tls->StatsFunction.update(CodeStats::CS_NumRPImms); | 291 Tls->StatsFunction.update(CodeStats::CS_NumRPImms); |
| 292 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms); | 292 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms); |
| 293 } | 293 } |
| 294 | 294 |
| 295 // These are predefined TimerStackIdT values. | 295 /// These are predefined TimerStackIdT values. |
| 296 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num }; | 296 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num }; |
| 297 | 297 |
| 298 // newTimerStackID() creates a new TimerStack in the global space. | 298 /// newTimerStackID() creates a new TimerStack in the global space. |
| 299 // It does not affect any TimerStack objects in TLS. | 299 /// It does not affect any TimerStack objects in TLS. |
| 300 TimerStackIdT newTimerStackID(const IceString &Name); | 300 TimerStackIdT newTimerStackID(const IceString &Name); |
| 301 // dumpTimers() dumps the global timer data. As such, one probably | 301 /// dumpTimers() dumps the global timer data. As such, one probably |
| 302 // wants to call mergeTimerStacks() as a prerequisite. | 302 /// wants to call mergeTimerStacks() as a prerequisite. |
| 303 void dumpTimers(TimerStackIdT StackID = TSK_Default, | 303 void dumpTimers(TimerStackIdT StackID = TSK_Default, |
| 304 bool DumpCumulative = true); | 304 bool DumpCumulative = true); |
| 305 // The following methods affect only the calling thread's TLS timer | 305 /// The following methods affect only the calling thread's TLS timer |
| 306 // data. | 306 /// data. |
| 307 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name); | 307 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name); |
| 308 void pushTimer(TimerIdT ID, TimerStackIdT StackID); | 308 void pushTimer(TimerIdT ID, TimerStackIdT StackID); |
| 309 void popTimer(TimerIdT ID, TimerStackIdT StackID); | 309 void popTimer(TimerIdT ID, TimerStackIdT StackID); |
| 310 void resetTimer(TimerStackIdT StackID); | 310 void resetTimer(TimerStackIdT StackID); |
| 311 void setTimerName(TimerStackIdT StackID, const IceString &NewName); | 311 void setTimerName(TimerStackIdT StackID, const IceString &NewName); |
| 312 | 312 |
| 313 // This is the first work item sequence number that the parser | 313 /// This is the first work item sequence number that the parser |
| 314 // produces, and correspondingly the first sequence number that the | 314 /// produces, and correspondingly the first sequence number that the |
| 315 // emitter thread will wait for. Start numbering at 1 to leave room | 315 /// emitter thread will wait for. Start numbering at 1 to leave room |
| 316 // for a sentinel, in case e.g. we wish to inject items with a | 316 /// for a sentinel, in case e.g. we wish to inject items with a |
| 317 // special sequence number that may be executed out of order. | 317 /// special sequence number that may be executed out of order. |
| 318 static uint32_t getFirstSequenceNumber() { return 1; } | 318 static uint32_t getFirstSequenceNumber() { return 1; } |
| 319 // Adds a newly parsed and constructed function to the Cfg work | 319 /// Adds a newly parsed and constructed function to the Cfg work |
| 320 // queue. Notifies any idle workers that a new function is | 320 /// queue. Notifies any idle workers that a new function is |
| 321 // available for translating. May block if the work queue is too | 321 /// available for translating. May block if the work queue is too |
| 322 // large, in order to control memory footprint. | 322 /// large, in order to control memory footprint. |
| 323 void optQueueBlockingPush(std::unique_ptr<Cfg> Func); | 323 void optQueueBlockingPush(std::unique_ptr<Cfg> Func); |
| 324 // Takes a Cfg from the work queue for translating. May block if | 324 /// Takes a Cfg from the work queue for translating. May block if |
| 325 // the work queue is currently empty. Returns nullptr if there is | 325 /// the work queue is currently empty. Returns nullptr if there is |
| 326 // no more work - the queue is empty and either end() has been | 326 /// no more work - the queue is empty and either end() has been |
| 327 // called or the Sequential flag was set. | 327 /// called or the Sequential flag was set. |
| 328 std::unique_ptr<Cfg> optQueueBlockingPop(); | 328 std::unique_ptr<Cfg> optQueueBlockingPop(); |
| 329 // Notifies that no more work will be added to the work queue. | 329 /// Notifies that no more work will be added to the work queue. |
| 330 void optQueueNotifyEnd() { OptQ.notifyEnd(); } | 330 void optQueueNotifyEnd() { OptQ.notifyEnd(); } |
| 331 | 331 |
| 332 // Emit file header for output file. | 332 /// Emit file header for output file. |
| 333 void emitFileHeader(); | 333 void emitFileHeader(); |
| 334 | 334 |
| 335 void lowerConstants(); | 335 void lowerConstants(); |
| 336 | 336 |
| 337 void emitQueueBlockingPush(EmitterWorkItem *Item); | 337 void emitQueueBlockingPush(EmitterWorkItem *Item); |
| 338 EmitterWorkItem *emitQueueBlockingPop(); | 338 EmitterWorkItem *emitQueueBlockingPop(); |
| 339 void emitQueueNotifyEnd() { EmitQ.notifyEnd(); } | 339 void emitQueueNotifyEnd() { EmitQ.notifyEnd(); } |
| 340 | 340 |
| 341 void initParserThread() { | 341 void initParserThread() { |
| 342 ThreadContext *Tls = new ThreadContext(); | 342 ThreadContext *Tls = new ThreadContext(); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 } | 387 } |
| 388 if (BuildDefs::dump()) { | 388 if (BuildDefs::dump()) { |
| 389 // Do a separate loop over AllThreadContexts to avoid holding | 389 // Do a separate loop over AllThreadContexts to avoid holding |
| 390 // two locks at once. | 390 // two locks at once. |
| 391 auto Stats = getStatsCumulative(); | 391 auto Stats = getStatsCumulative(); |
| 392 for (ThreadContext *TLS : AllThreadContexts) | 392 for (ThreadContext *TLS : AllThreadContexts) |
| 393 Stats->add(TLS->StatsCumulative); | 393 Stats->add(TLS->StatsCumulative); |
| 394 } | 394 } |
| 395 } | 395 } |
| 396 | 396 |
| 397 // Translation thread startup routine. | 397 /// Translation thread startup routine. |
| 398 void translateFunctionsWrapper(ThreadContext *MyTLS) { | 398 void translateFunctionsWrapper(ThreadContext *MyTLS) { |
| 399 ICE_TLS_SET_FIELD(TLS, MyTLS); | 399 ICE_TLS_SET_FIELD(TLS, MyTLS); |
| 400 translateFunctions(); | 400 translateFunctions(); |
| 401 } | 401 } |
| 402 // Translate functions from the Cfg queue until the queue is empty. | 402 /// Translate functions from the Cfg queue until the queue is empty. |
| 403 void translateFunctions(); | 403 void translateFunctions(); |
| 404 | 404 |
| 405 // Emitter thread startup routine. | 405 /// Emitter thread startup routine. |
| 406 void emitterWrapper(ThreadContext *MyTLS) { | 406 void emitterWrapper(ThreadContext *MyTLS) { |
| 407 ICE_TLS_SET_FIELD(TLS, MyTLS); | 407 ICE_TLS_SET_FIELD(TLS, MyTLS); |
| 408 emitItems(); | 408 emitItems(); |
| 409 } | 409 } |
| 410 // Emit functions and global initializers from the emitter queue | 410 /// Emit functions and global initializers from the emitter queue |
| 411 // until the queue is empty. | 411 /// until the queue is empty. |
| 412 void emitItems(); | 412 void emitItems(); |
| 413 | 413 |
| 414 // Uses DataLowering to lower Globals. Side effects: | 414 /// Uses DataLowering to lower Globals. Side effects: |
| 415 // - discards the initializer list for the global variable in Globals. | 415 /// - discards the initializer list for the global variable in Globals. |
| 416 // - clears the Globals array. | 416 /// - clears the Globals array. |
| 417 void lowerGlobals(const IceString &SectionSuffix); | 417 void lowerGlobals(const IceString &SectionSuffix); |
| 418 | 418 |
| 419 // Lowers the profile information. | 419 /// Lowers the profile information. |
| 420 void lowerProfileData(); | 420 void lowerProfileData(); |
| 421 | 421 |
| 422 // Utility function to match a symbol name against a match string. | 422 /// Utility function to match a symbol name against a match string. |
| 423 // This is used in a few cases where we want to take some action on | 423 /// This is used in a few cases where we want to take some action on |
| 424 // a particular function or symbol based on a command-line argument, | 424 /// a particular function or symbol based on a command-line argument, |
| 425 // such as changing the verbose level for a particular function. An | 425 /// such as changing the verbose level for a particular function. An |
| 426 // empty Match argument means match everything. Returns true if | 426 /// empty Match argument means match everything. Returns true if |
| 427 // there is a match. | 427 /// there is a match. |
| 428 static bool matchSymbolName(const IceString &SymbolName, | 428 static bool matchSymbolName(const IceString &SymbolName, |
| 429 const IceString &Match) { | 429 const IceString &Match) { |
| 430 return Match.empty() || Match == SymbolName; | 430 return Match.empty() || Match == SymbolName; |
| 431 } | 431 } |
| 432 | 432 |
| 433 // Return the randomization cookie for diversification. | 433 /// Return the randomization cookie for diversification. |
| 434 // Initialize the cookie if necessary | 434 /// Initialize the cookie if necessary |
| 435 uint32_t getRandomizationCookie() const { return RandomizationCookie; } | 435 uint32_t getRandomizationCookie() const { return RandomizationCookie; } |
| 436 | 436 |
| 437 private: | 437 private: |
| 438 // Try to ensure mutexes are allocated on separate cache lines. | 438 // Try to ensure mutexes are allocated on separate cache lines. |
| 439 | 439 |
| 440 // Destructors collaborate with Allocator | 440 // Destructors collaborate with Allocator |
| 441 ICE_CACHELINE_BOUNDARY; | 441 ICE_CACHELINE_BOUNDARY; |
| 442 // Managed by getAllocator() | 442 // Managed by getAllocator() |
| 443 GlobalLockType AllocLock; | 443 GlobalLockType AllocLock; |
| 444 ArenaAllocator<> Allocator; | 444 ArenaAllocator<> Allocator; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 463 // Managed by getStatsCumulative() | 463 // Managed by getStatsCumulative() |
| 464 GlobalLockType StatsLock; | 464 GlobalLockType StatsLock; |
| 465 CodeStats StatsCumulative; | 465 CodeStats StatsCumulative; |
| 466 | 466 |
| 467 ICE_CACHELINE_BOUNDARY; | 467 ICE_CACHELINE_BOUNDARY; |
| 468 // Managed by getTimers() | 468 // Managed by getTimers() |
| 469 GlobalLockType TimerLock; | 469 GlobalLockType TimerLock; |
| 470 TimerList Timers; | 470 TimerList Timers; |
| 471 | 471 |
| 472 ICE_CACHELINE_BOUNDARY; | 472 ICE_CACHELINE_BOUNDARY; |
| 473 // StrLock is a global lock on the dump and emit output streams. | 473 /// StrLock is a global lock on the dump and emit output streams. |
| 474 typedef std::mutex StrLockType; | 474 typedef std::mutex StrLockType; |
| 475 StrLockType StrLock; | 475 StrLockType StrLock; |
| 476 Ostream *StrDump; // Stream for dumping / diagnostics | 476 Ostream *StrDump; /// Stream for dumping / diagnostics |
| 477 Ostream *StrEmit; // Stream for code emission | 477 Ostream *StrEmit; /// Stream for code emission |
| 478 Ostream *StrError; // Stream for logging errors. | 478 Ostream *StrError; /// Stream for logging errors. |
| 479 | 479 |
| 480 ICE_CACHELINE_BOUNDARY; | 480 ICE_CACHELINE_BOUNDARY; |
| 481 | 481 |
| 482 Intrinsics IntrinsicsInfo; | 482 Intrinsics IntrinsicsInfo; |
| 483 const ClFlags &Flags; | 483 const ClFlags &Flags; |
| 484 RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg. | 484 RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg. |
| 485 // TODO(jpp): move to EmitterContext. | 485 // TODO(jpp): move to EmitterContext. |
| 486 std::unique_ptr<ELFObjectWriter> ObjectWriter; | 486 std::unique_ptr<ELFObjectWriter> ObjectWriter; |
| 487 BoundedProducerConsumerQueue<Cfg> OptQ; | 487 BoundedProducerConsumerQueue<Cfg> OptQ; |
| 488 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ; | 488 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ; |
| 489 // DataLowering is only ever used by a single thread at a time (either in | 489 // DataLowering is only ever used by a single thread at a time (either in |
| 490 // emitItems(), or in IceCompiler::run before the compilation is over.) | 490 // emitItems(), or in IceCompiler::run before the compilation is over.) |
| 491 // TODO(jpp): move to EmitterContext. | 491 // TODO(jpp): move to EmitterContext. |
| 492 std::unique_ptr<TargetDataLowering> DataLowering; | 492 std::unique_ptr<TargetDataLowering> DataLowering; |
| 493 // If !HasEmittedCode, SubZero will accumulate all Globals (which are "true" | 493 /// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true" |
| 494 // program global variables) until the first code WorkItem is seen. | 494 /// program global variables) until the first code WorkItem is seen. |
| 495 // TODO(jpp): move to EmitterContext. | 495 // TODO(jpp): move to EmitterContext. |
| 496 bool HasSeenCode = false; | 496 bool HasSeenCode = false; |
| 497 // TODO(jpp): move to EmitterContext. | 497 // TODO(jpp): move to EmitterContext. |
| 498 VariableDeclarationList Globals; | 498 VariableDeclarationList Globals; |
| 499 // TODO(jpp): move to EmitterContext. | 499 // TODO(jpp): move to EmitterContext. |
| 500 VariableDeclaration *ProfileBlockInfoVarDecl; | 500 VariableDeclaration *ProfileBlockInfoVarDecl; |
| 501 | 501 |
| 502 LockedPtr<ArenaAllocator<>> getAllocator() { | 502 LockedPtr<ArenaAllocator<>> getAllocator() { |
| 503 return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock); | 503 return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock); |
| 504 } | 504 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 | 541 |
| 542 // Randomization Cookie | 542 // Randomization Cookie |
| 543 // Managed by getRandomizationCookie() | 543 // Managed by getRandomizationCookie() |
| 544 GlobalLockType RandomizationCookieLock; | 544 GlobalLockType RandomizationCookieLock; |
| 545 uint32_t RandomizationCookie = 0; | 545 uint32_t RandomizationCookie = 0; |
| 546 | 546 |
| 547 public: | 547 public: |
| 548 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); } | 548 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); } |
| 549 }; | 549 }; |
| 550 | 550 |
| 551 // Helper class to push and pop a timer marker. The constructor | 551 /// Helper class to push and pop a timer marker. The constructor |
| 552 // pushes a marker, and the destructor pops it. This is for | 552 /// pushes a marker, and the destructor pops it. This is for |
| 553 // convenient timing of regions of code. | 553 /// convenient timing of regions of code. |
| 554 class TimerMarker { | 554 class TimerMarker { |
| 555 TimerMarker() = delete; | 555 TimerMarker() = delete; |
| 556 TimerMarker(const TimerMarker &) = delete; | 556 TimerMarker(const TimerMarker &) = delete; |
| 557 TimerMarker &operator=(const TimerMarker &) = delete; | 557 TimerMarker &operator=(const TimerMarker &) = delete; |
| 558 | 558 |
| 559 public: | 559 public: |
| 560 TimerMarker(TimerIdT ID, GlobalContext *Ctx, | 560 TimerMarker(TimerIdT ID, GlobalContext *Ctx, |
| 561 TimerStackIdT StackID = GlobalContext::TSK_Default) | 561 TimerStackIdT StackID = GlobalContext::TSK_Default) |
| 562 : ID(ID), Ctx(Ctx), StackID(StackID) { | 562 : ID(ID), Ctx(Ctx), StackID(StackID) { |
| 563 if (BuildDefs::dump()) | 563 if (BuildDefs::dump()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 578 | 578 |
| 579 private: | 579 private: |
| 580 void push(); | 580 void push(); |
| 581 void pushCfg(const Cfg *Func); | 581 void pushCfg(const Cfg *Func); |
| 582 const TimerIdT ID; | 582 const TimerIdT ID; |
| 583 GlobalContext *Ctx; | 583 GlobalContext *Ctx; |
| 584 const TimerStackIdT StackID; | 584 const TimerStackIdT StackID; |
| 585 bool Active = false; | 585 bool Active = false; |
| 586 }; | 586 }; |
| 587 | 587 |
| 588 // Helper class for locking the streams and then automatically | 588 /// Helper class for locking the streams and then automatically |
| 589 // unlocking them. | 589 /// unlocking them. |
| 590 class OstreamLocker { | 590 class OstreamLocker { |
| 591 private: | 591 private: |
| 592 OstreamLocker() = delete; | 592 OstreamLocker() = delete; |
| 593 OstreamLocker(const OstreamLocker &) = delete; | 593 OstreamLocker(const OstreamLocker &) = delete; |
| 594 OstreamLocker &operator=(const OstreamLocker &) = delete; | 594 OstreamLocker &operator=(const OstreamLocker &) = delete; |
| 595 | 595 |
| 596 public: | 596 public: |
| 597 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } | 597 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } |
| 598 ~OstreamLocker() { Ctx->unlockStr(); } | 598 ~OstreamLocker() { Ctx->unlockStr(); } |
| 599 | 599 |
| 600 private: | 600 private: |
| 601 GlobalContext *const Ctx; | 601 GlobalContext *const Ctx; |
| 602 }; | 602 }; |
| 603 | 603 |
| 604 } // end of namespace Ice | 604 } // end of namespace Ice |
| 605 | 605 |
| 606 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H | 606 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H |
| OLD | NEW |