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