blob: 1e23a36381546ef0ab303e0a276f01fb4e19bc75 [file] [log] [blame]
Jim Stichnothf7c9a142014-04-29 10:52:43 -07001//===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file declares aspects of the compilation that persist across
11// multiple functions.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H
16#define SUBZERO_SRC_ICEGLOBALCONTEXT_H
17
Jim Stichnothf7c9a142014-04-29 10:52:43 -070018#include "IceDefs.h"
Karl Schimpf9d98d792014-10-13 15:01:08 -070019#include "IceClFlags.h"
Jan Voung3bd9f1a2014-06-18 10:50:57 -070020#include "IceIntrinsics.h"
Matt Wala1bd2fce2014-08-08 14:02:09 -070021#include "IceRNG.h"
Jim Stichnothbbca7542015-02-11 16:08:31 -080022#include "IceThreading.h"
Jim Stichnoth8363a062014-10-07 10:02:38 -070023#include "IceTimerTree.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070024#include "IceTypes.h"
Jim Stichnothfa4efea2015-01-27 05:06:03 -080025#include "IceUtils.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070026
John Porto67f8de92015-06-25 10:14:17 -070027#include <array>
28#include <functional>
29#include <mutex>
30#include <thread>
31#include <type_traits>
32#include <vector>
33
Jim Stichnothf7c9a142014-04-29 10:52:43 -070034namespace Ice {
35
Jim Stichnoth989a7032014-08-08 10:13:44 -070036class ClFlags;
Jim Stichnothe4a8f402015-01-20 12:52:51 -080037class ConstantPool;
Jim Stichnothbbca7542015-02-11 16:08:31 -080038class EmitterWorkItem;
Karl Schimpf9d98d792014-10-13 15:01:08 -070039class FuncSigType;
Jim Stichnoth989a7032014-08-08 10:13:44 -070040
Jim Stichnothe4a8f402015-01-20 12:52:51 -080041// LockedPtr is a way to provide automatically locked access to some object.
42template <typename T> class LockedPtr {
43 LockedPtr() = delete;
44 LockedPtr(const LockedPtr &) = delete;
45 LockedPtr &operator=(const LockedPtr &) = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070046
Jim Stichnoth18735602014-09-16 19:59:35 -070047public:
Jim Stichnothe4a8f402015-01-20 12:52:51 -080048 LockedPtr(T *Value, GlobalLockType *Lock) : Value(Value), Lock(Lock) {
49 Lock->lock();
50 }
51 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) {
52 Other.Value = nullptr;
53 Other.Lock = nullptr;
54 }
55 ~LockedPtr() { Lock->unlock(); }
56 T *operator->() const { return Value; }
Jim Stichnoth18735602014-09-16 19:59:35 -070057
58private:
Jim Stichnothe4a8f402015-01-20 12:52:51 -080059 T *Value;
60 GlobalLockType *Lock;
Jim Stichnoth18735602014-09-16 19:59:35 -070061};
62
Jim Stichnothf7c9a142014-04-29 10:52:43 -070063class GlobalContext {
Jim Stichnothc6ead202015-02-24 09:30:30 -080064 GlobalContext() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070065 GlobalContext(const GlobalContext &) = delete;
66 GlobalContext &operator=(const GlobalContext &) = delete;
67
Jim Stichnothe4a8f402015-01-20 12:52:51 -080068 // CodeStats collects rudimentary statistics during translation.
69 class CodeStats {
70 CodeStats(const CodeStats &) = delete;
71 CodeStats &operator=(const CodeStats &) = default;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080072#define CODESTATS_TABLE \
73 /* dump string, enum value */ \
74 X("Inst Count ", InstCount) \
75 X("Regs Saved ", RegsSaved) \
76 X("Frame Bytes ", FrameByte) \
77 X("Spills ", NumSpills) \
Qining Lu253dc8a2015-06-22 10:10:23 -070078 X("Fills ", NumFills) \
79 X("R/P Imms ", NumRPImms)
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080080 //#define X(str, tag)
Jim Stichnothe4a8f402015-01-20 12:52:51 -080081
82 public:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080083 enum CSTag {
84#define X(str, tag) CS_##tag,
85 CODESTATS_TABLE
86#undef X
87 CS_NUM
88 };
89 CodeStats() { reset(); }
90 void reset() { Stats.fill(0); }
91 void update(CSTag Tag, uint32_t Count = 1) {
92 assert(Tag < Stats.size());
93 Stats[Tag] += Count;
94 }
95 void add(const CodeStats &Other) {
96 for (uint32_t i = 0; i < Stats.size(); ++i)
97 Stats[i] += Other.Stats[i];
98 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -080099 void dump(const IceString &Name, Ostream &Str);
100
101 private:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800102 std::array<uint32_t, CS_NUM> Stats;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800103 };
104
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800105 // TimerList is a vector of TimerStack objects, with extra methods
106 // to initialize and merge these vectors.
107 class TimerList : public std::vector<TimerStack> {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800108 TimerList(const TimerList &) = delete;
109 TimerList &operator=(const TimerList &) = delete;
110
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800111 public:
Jim Stichnothc6ead202015-02-24 09:30:30 -0800112 TimerList() = default;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800113 // initInto() initializes a target list of timers based on the
114 // current list. In particular, it creates the same number of
115 // timers, in the same order, with the same names, but initially
116 // empty of timing data.
117 void initInto(TimerList &Dest) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700118 if (!BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800119 return;
120 Dest.clear();
121 for (const TimerStack &Stack : *this) {
122 Dest.push_back(TimerStack(Stack.getName()));
123 }
124 }
125 void mergeFrom(TimerList &Src) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700126 if (!BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800127 return;
128 assert(size() == Src.size());
129 size_type i = 0;
130 for (TimerStack &Stack : *this) {
131 assert(Stack.getName() == Src[i].getName());
132 Stack.mergeFrom(Src[i]);
133 ++i;
134 }
135 }
136 };
137
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800138 // ThreadContext contains thread-local data. This data can be
139 // combined/reduced as needed after all threads complete.
140 class ThreadContext {
141 ThreadContext(const ThreadContext &) = delete;
142 ThreadContext &operator=(const ThreadContext &) = delete;
143
144 public:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700145 ThreadContext() = default;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800146 CodeStats StatsFunction;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800147 CodeStats StatsCumulative;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800148 TimerList Timers;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800149 };
150
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700151public:
Karl Schimpf2f67b922015-04-22 15:20:16 -0700152 // 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 GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
155 ELFStreamer *ELFStreamer, const ClFlags &Flags);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700156 ~GlobalContext();
157
Karl Schimpf2f67b922015-04-22 15:20:16 -0700158 //
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
161 // streams via lockStr() and unlockStr(). The OstreamLocker class
162 // can be used to conveniently manage this.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800163 //
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
166 // the stream and do something with it, and finally the thread
167 // releases the stream lock. This allows large chunks of output to
168 // be dumped or emitted without risking interleaving from multiple
169 // threads.
170 void lockStr() { StrLock.lock(); }
171 void unlockStr() { StrLock.unlock(); }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700172 Ostream &getStrDump() { return *StrDump; }
Karl Schimpf2f67b922015-04-22 15:20:16 -0700173 Ostream &getStrError() { return *StrError; }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700174 Ostream &getStrEmit() { return *StrEmit; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700175
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800176 LockedPtr<ErrorCode> getErrorStatus() {
177 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock);
178 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700179
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700180 // When emitting assembly, we allow a string to be prepended to
181 // names of translated functions. This makes it easier to create an
182 // execution test against a reference translator like llc, with both
183 // translators using the same bitcode as input.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700184 IceString mangleName(const IceString &Name) const;
185
186 // Manage Constants.
187 // getConstant*() functions are not const because they might add
188 // something to the constant pool.
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800189 Constant *getConstantInt(Type Ty, int64_t Value);
190 Constant *getConstantInt1(int8_t ConstantInt1);
191 Constant *getConstantInt8(int8_t ConstantInt8);
192 Constant *getConstantInt16(int16_t ConstantInt16);
193 Constant *getConstantInt32(int32_t ConstantInt32);
194 Constant *getConstantInt64(int64_t ConstantInt64);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700195 Constant *getConstantFloat(float Value);
196 Constant *getConstantDouble(double Value);
197 // Returns a symbolic constant.
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800198 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name,
199 bool SuppressMangling);
Jan Voung261cae32015-02-01 10:31:03 -0800200 Constant *getConstantExternSym(const IceString &Name);
Matt Walad8f4a7d2014-06-18 09:55:03 -0700201 // Returns an undef.
202 Constant *getConstantUndef(Type Ty);
203 // Returns a zero value.
204 Constant *getConstantZero(Type Ty);
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700205 // getConstantPool() returns a copy of the constant pool for
206 // constants of a given type.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800207 ConstantList getConstantPool(Type Ty);
Jan Voung261cae32015-02-01 10:31:03 -0800208 // Returns a copy of the list of external symbols.
209 ConstantList getConstantExternSyms();
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700210
Jim Stichnoth989a7032014-08-08 10:13:44 -0700211 const ClFlags &getFlags() const { return Flags; }
212
Karl Schimpf6fcbddd2014-11-06 09:49:24 -0800213 bool isIRGenerationDisabled() const {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800214 return getFlags().getDisableIRGeneration();
Karl Schimpf6fcbddd2014-11-06 09:49:24 -0800215 }
216
John Porto1bec8bc2015-06-22 10:51:13 -0700217 // Allocate data of type T using the global allocator. We allow entities
218 // allocated from this global allocator to be either trivially or
219 // non-trivially destructible. We optimize the case when T is trivially
220 // destructible by not registering a destructor. Destructors will be invoked
221 // during GlobalContext destruction in the reverse object creation order.
222 template <typename T>
223 typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type *
224 allocate() {
225 return getAllocator()->Allocate<T>();
226 }
227
228 template <typename T>
229 typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type *
230 allocate() {
231 T *Ret = getAllocator()->Allocate<T>();
232 getDestructors()->emplace_back([Ret]() { Ret->~T(); });
233 return Ret;
234 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700235
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700236 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
237
Matt Wala1bd2fce2014-08-08 14:02:09 -0700238 // TODO(wala,stichnot): Make the RNG play nicely with multithreaded
239 // translation.
240 RandomNumberGenerator &getRNG() { return RNG; }
241
Jan Voung08c3bcd2014-12-01 17:55:16 -0800242 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); }
243
Jim Stichnoth18735602014-09-16 19:59:35 -0700244 // Reset stats at the beginning of a function.
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800245 void resetStats() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700246 if (BuildDefs::dump())
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800247 ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset();
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800248 }
Jim Stichnothff9c7062014-09-18 04:50:49 -0700249 void dumpStats(const IceString &Name, bool Final = false);
Jim Stichnoth18735602014-09-16 19:59:35 -0700250 void statsUpdateEmitted(uint32_t InstCount) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800251 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800252 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700253 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
254 Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount);
255 Tls->StatsCumulative.update(CodeStats::CS_InstCount, InstCount);
Jim Stichnoth18735602014-09-16 19:59:35 -0700256 }
257 void statsUpdateRegistersSaved(uint32_t Num) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800258 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800259 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700260 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
261 Tls->StatsFunction.update(CodeStats::CS_RegsSaved, Num);
262 Tls->StatsCumulative.update(CodeStats::CS_RegsSaved, Num);
Jim Stichnoth18735602014-09-16 19:59:35 -0700263 }
264 void statsUpdateFrameBytes(uint32_t Bytes) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800265 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800266 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700267 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
268 Tls->StatsFunction.update(CodeStats::CS_FrameByte, Bytes);
269 Tls->StatsCumulative.update(CodeStats::CS_FrameByte, Bytes);
Jim Stichnoth18735602014-09-16 19:59:35 -0700270 }
271 void statsUpdateSpills() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800272 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800273 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700274 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
275 Tls->StatsFunction.update(CodeStats::CS_NumSpills);
276 Tls->StatsCumulative.update(CodeStats::CS_NumSpills);
Jim Stichnoth18735602014-09-16 19:59:35 -0700277 }
278 void statsUpdateFills() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800279 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800280 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700281 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
282 Tls->StatsFunction.update(CodeStats::CS_NumFills);
283 Tls->StatsCumulative.update(CodeStats::CS_NumFills);
Jim Stichnoth18735602014-09-16 19:59:35 -0700284 }
285
Qining Lu253dc8a2015-06-22 10:10:23 -0700286 // Number of Randomized or Pooled Immediates
287 void statsUpdateRPImms() {
288 if (!getFlags().getDumpStats())
289 return;
290 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
291 Tls->StatsFunction.update(CodeStats::CS_NumRPImms);
292 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms);
293 }
294
Jim Stichnoth8363a062014-10-07 10:02:38 -0700295 // These are predefined TimerStackIdT values.
Jim Stichnothdd842db2015-01-27 12:53:53 -0800296 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num };
Jim Stichnoth8363a062014-10-07 10:02:38 -0700297
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800298 // newTimerStackID() creates a new TimerStack in the global space.
299 // It does not affect any TimerStack objects in TLS.
Jim Stichnoth8363a062014-10-07 10:02:38 -0700300 TimerStackIdT newTimerStackID(const IceString &Name);
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800301 // dumpTimers() dumps the global timer data. As such, one probably
302 // wants to call mergeTimerStacks() as a prerequisite.
Jim Stichnoth8363a062014-10-07 10:02:38 -0700303 void dumpTimers(TimerStackIdT StackID = TSK_Default,
304 bool DumpCumulative = true);
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800305 // The following methods affect only the calling thread's TLS timer
306 // data.
307 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name);
308 void pushTimer(TimerIdT ID, TimerStackIdT StackID);
309 void popTimer(TimerIdT ID, TimerStackIdT StackID);
310 void resetTimer(TimerStackIdT StackID);
311 void setTimerName(TimerStackIdT StackID, const IceString &NewName);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700312
Jim Stichnothbbca7542015-02-11 16:08:31 -0800313 // This is the first work item sequence number that the parser
314 // produces, and correspondingly the first sequence number that the
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
317 // special sequence number that may be executed out of order.
318 static uint32_t getFirstSequenceNumber() { return 1; }
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800319 // Adds a newly parsed and constructed function to the Cfg work
320 // queue. Notifies any idle workers that a new function is
321 // available for translating. May block if the work queue is too
322 // large, in order to control memory footprint.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800323 void optQueueBlockingPush(std::unique_ptr<Cfg> Func);
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800324 // 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 // no more work - the queue is empty and either end() has been
327 // called or the Sequential flag was set.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800328 std::unique_ptr<Cfg> optQueueBlockingPop();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800329 // Notifies that no more work will be added to the work queue.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800330 void optQueueNotifyEnd() { OptQ.notifyEnd(); }
331
Jan Voungfb792842015-06-11 15:27:50 -0700332 // Emit file header for output file.
333 void emitFileHeader();
334
John Porto8b1a7052015-06-17 13:20:08 -0700335 void lowerConstants();
336
Jim Stichnothbbca7542015-02-11 16:08:31 -0800337 void emitQueueBlockingPush(EmitterWorkItem *Item);
338 EmitterWorkItem *emitQueueBlockingPop();
339 void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800340
Jan Voung44c3a802015-03-27 16:29:08 -0700341 void initParserThread() {
342 ThreadContext *Tls = new ThreadContext();
343 auto Timers = getTimers();
344 Timers->initInto(Tls->Timers);
345 AllThreadContexts.push_back(Tls);
346 ICE_TLS_SET_FIELD(TLS, Tls);
347 }
348
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800349 void startWorkerThreads() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800350 size_t NumWorkers = getFlags().getNumTranslationThreads();
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800351 auto Timers = getTimers();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800352 for (size_t i = 0; i < NumWorkers; ++i) {
353 ThreadContext *WorkerTLS = new ThreadContext();
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800354 Timers->initInto(WorkerTLS->Timers);
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800355 AllThreadContexts.push_back(WorkerTLS);
356 TranslationThreads.push_back(std::thread(
357 &GlobalContext::translateFunctionsWrapper, this, WorkerTLS));
358 }
359 if (NumWorkers) {
Jim Stichnothbbca7542015-02-11 16:08:31 -0800360 ThreadContext *WorkerTLS = new ThreadContext();
361 Timers->initInto(WorkerTLS->Timers);
362 AllThreadContexts.push_back(WorkerTLS);
363 EmitterThreads.push_back(
364 std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS));
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800365 }
366 }
367
368 void waitForWorkerThreads() {
Jim Stichnothbbca7542015-02-11 16:08:31 -0800369 optQueueNotifyEnd();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800370 for (std::thread &Worker : TranslationThreads) {
371 Worker.join();
372 }
373 TranslationThreads.clear();
Jim Stichnothbbca7542015-02-11 16:08:31 -0800374
375 // Only notify the emit queue to end after all the translation
376 // threads have ended.
377 emitQueueNotifyEnd();
378 for (std::thread &Worker : EmitterThreads) {
379 Worker.join();
380 }
381 EmitterThreads.clear();
382
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700383 if (BuildDefs::dump()) {
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800384 auto Timers = getTimers();
385 for (ThreadContext *TLS : AllThreadContexts)
386 Timers->mergeFrom(TLS->Timers);
387 }
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700388 if (BuildDefs::dump()) {
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800389 // Do a separate loop over AllThreadContexts to avoid holding
390 // two locks at once.
391 auto Stats = getStatsCumulative();
392 for (ThreadContext *TLS : AllThreadContexts)
393 Stats->add(TLS->StatsCumulative);
394 }
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800395 }
396
397 // Translation thread startup routine.
398 void translateFunctionsWrapper(ThreadContext *MyTLS) {
399 ICE_TLS_SET_FIELD(TLS, MyTLS);
400 translateFunctions();
401 }
402 // Translate functions from the Cfg queue until the queue is empty.
403 void translateFunctions();
404
Jim Stichnothbbca7542015-02-11 16:08:31 -0800405 // Emitter thread startup routine.
406 void emitterWrapper(ThreadContext *MyTLS) {
407 ICE_TLS_SET_FIELD(TLS, MyTLS);
408 emitItems();
409 }
410 // Emit functions and global initializers from the emitter queue
411 // until the queue is empty.
412 void emitItems();
413
John Porto1bec8bc2015-06-22 10:51:13 -0700414 // Uses DataLowering to lower Globals. Side effects:
415 // - discards the initializer list for the global variable in Globals.
416 // - clears the Globals array.
John Porto8b1a7052015-06-17 13:20:08 -0700417 void lowerGlobals(const IceString &SectionSuffix);
418
419 // Lowers the profile information.
420 void lowerProfileData();
421
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800422 // 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 // a particular function or symbol based on a command-line argument,
425 // such as changing the verbose level for a particular function. An
426 // empty Match argument means match everything. Returns true if
427 // there is a match.
428 static bool matchSymbolName(const IceString &SymbolName,
429 const IceString &Match) {
430 return Match.empty() || Match == SymbolName;
431 }
432
Qining Lu253dc8a2015-06-22 10:10:23 -0700433 // Return the randomization cookie for diversification.
434 // Initialize the cookie if necessary
435 uint32_t getRandomizationCookie() const { return RandomizationCookie; }
436
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800437private:
438 // Try to ensure mutexes are allocated on separate cache lines.
439
John Porto1bec8bc2015-06-22 10:51:13 -0700440 // Destructors collaborate with Allocator
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800441 ICE_CACHELINE_BOUNDARY;
442 // Managed by getAllocator()
443 GlobalLockType AllocLock;
444 ArenaAllocator<> Allocator;
445
446 ICE_CACHELINE_BOUNDARY;
John Porto1bec8bc2015-06-22 10:51:13 -0700447 // Managed by getDestructors()
448 typedef std::vector<std::function<void()>> DestructorArray;
449 GlobalLockType DestructorsLock;
450 DestructorArray Destructors;
451
452 ICE_CACHELINE_BOUNDARY;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800453 // Managed by getConstantPool()
454 GlobalLockType ConstPoolLock;
455 std::unique_ptr<ConstantPool> ConstPool;
456
457 ICE_CACHELINE_BOUNDARY;
458 // Managed by getErrorStatus()
459 GlobalLockType ErrorStatusLock;
460 ErrorCode ErrorStatus;
461
462 ICE_CACHELINE_BOUNDARY;
463 // Managed by getStatsCumulative()
464 GlobalLockType StatsLock;
465 CodeStats StatsCumulative;
466
467 ICE_CACHELINE_BOUNDARY;
468 // Managed by getTimers()
469 GlobalLockType TimerLock;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800470 TimerList Timers;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800471
472 ICE_CACHELINE_BOUNDARY;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800473 // StrLock is a global lock on the dump and emit output streams.
474 typedef std::mutex StrLockType;
475 StrLockType StrLock;
Jim Stichnoth620ad732015-04-28 14:12:20 -0700476 Ostream *StrDump; // Stream for dumping / diagnostics
477 Ostream *StrEmit; // Stream for code emission
Karl Schimpf2f67b922015-04-22 15:20:16 -0700478 Ostream *StrError; // Stream for logging errors.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700479
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800480 ICE_CACHELINE_BOUNDARY;
481
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700482 Intrinsics IntrinsicsInfo;
Jim Stichnoth989a7032014-08-08 10:13:44 -0700483 const ClFlags &Flags;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800484 RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg.
John Porto8b1a7052015-06-17 13:20:08 -0700485 // TODO(jpp): move to EmitterContext.
Jan Voung08c3bcd2014-12-01 17:55:16 -0800486 std::unique_ptr<ELFObjectWriter> ObjectWriter;
Jim Stichnothbbca7542015-02-11 16:08:31 -0800487 BoundedProducerConsumerQueue<Cfg> OptQ;
488 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ;
John Porto8b1a7052015-06-17 13:20:08 -0700489 // 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 // TODO(jpp): move to EmitterContext.
492 std::unique_ptr<TargetDataLowering> DataLowering;
493 // If !HasEmittedCode, SubZero will accumulate all Globals (which are "true"
494 // program global variables) until the first code WorkItem is seen.
495 // TODO(jpp): move to EmitterContext.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700496 bool HasSeenCode = false;
John Porto8b1a7052015-06-17 13:20:08 -0700497 // TODO(jpp): move to EmitterContext.
498 VariableDeclarationList Globals;
499 // TODO(jpp): move to EmitterContext.
John Porto1bec8bc2015-06-22 10:51:13 -0700500 VariableDeclaration *ProfileBlockInfoVarDecl;
Jim Stichnoth217dc082014-07-11 14:06:55 -0700501
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800502 LockedPtr<ArenaAllocator<>> getAllocator() {
503 return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock);
504 }
505 LockedPtr<ConstantPool> getConstPool() {
506 return LockedPtr<ConstantPool>(ConstPool.get(), &ConstPoolLock);
507 }
508 LockedPtr<CodeStats> getStatsCumulative() {
509 return LockedPtr<CodeStats>(&StatsCumulative, &StatsLock);
510 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800511 LockedPtr<TimerList> getTimers() {
512 return LockedPtr<TimerList>(&Timers, &TimerLock);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800513 }
John Porto1bec8bc2015-06-22 10:51:13 -0700514 LockedPtr<DestructorArray> getDestructors() {
515 return LockedPtr<DestructorArray>(&Destructors, &DestructorsLock);
516 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800517
John Porto8b1a7052015-06-17 13:20:08 -0700518 void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
519 if (Globls != nullptr)
520 Globals.insert(Globals.end(), Globls->begin(), Globls->end());
521 }
522
523 void lowerGlobalsIfNoCodeHasBeenSeen() {
524 if (HasSeenCode)
525 return;
526 constexpr char NoSuffix[] = "";
527 lowerGlobals(NoSuffix);
528 HasSeenCode = true;
529 }
530
Jim Stichnothbbca7542015-02-11 16:08:31 -0800531 llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
532 llvm::SmallVector<std::thread, 128> TranslationThreads;
533 llvm::SmallVector<std::thread, 128> EmitterThreads;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800534 // Each thread has its own TLS pointer which is also held in
535 // AllThreadContexts.
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800536 ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800537
Jim Stichnoth217dc082014-07-11 14:06:55 -0700538 // Private helpers for mangleName()
539 typedef llvm::SmallVector<char, 32> ManglerVector;
540 void incrementSubstitutions(ManglerVector &OldName) const;
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800541
Qining Lu253dc8a2015-06-22 10:10:23 -0700542 // Randomization Cookie
543 // Managed by getRandomizationCookie()
544 GlobalLockType RandomizationCookieLock;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700545 uint32_t RandomizationCookie = 0;
Qining Lu253dc8a2015-06-22 10:10:23 -0700546
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800547public:
548 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700549};
550
Jim Stichnothc4554d72014-09-30 16:49:38 -0700551// Helper class to push and pop a timer marker. The constructor
552// pushes a marker, and the destructor pops it. This is for
553// convenient timing of regions of code.
554class TimerMarker {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800555 TimerMarker() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700556 TimerMarker(const TimerMarker &) = delete;
557 TimerMarker &operator=(const TimerMarker &) = delete;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700558
559public:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800560 TimerMarker(TimerIdT ID, GlobalContext *Ctx,
561 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700562 : ID(ID), Ctx(Ctx), StackID(StackID) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700563 if (BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800564 push();
Jim Stichnothc4554d72014-09-30 16:49:38 -0700565 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800566 TimerMarker(TimerIdT ID, const Cfg *Func,
567 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700568 : ID(ID), Ctx(nullptr), StackID(StackID) {
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800569 // Ctx gets set at the beginning of pushCfg().
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700570 if (BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800571 pushCfg(Func);
572 }
Jim Stichnoth8363a062014-10-07 10:02:38 -0700573
Jim Stichnothc4554d72014-09-30 16:49:38 -0700574 ~TimerMarker() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700575 if (BuildDefs::dump() && Active)
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800576 Ctx->popTimer(ID, StackID);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700577 }
578
579private:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800580 void push();
581 void pushCfg(const Cfg *Func);
582 const TimerIdT ID;
583 GlobalContext *Ctx;
584 const TimerStackIdT StackID;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700585 bool Active = false;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700586};
587
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800588// Helper class for locking the streams and then automatically
589// unlocking them.
590class OstreamLocker {
591private:
592 OstreamLocker() = delete;
593 OstreamLocker(const OstreamLocker &) = delete;
594 OstreamLocker &operator=(const OstreamLocker &) = delete;
595
596public:
597 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); }
598 ~OstreamLocker() { Ctx->unlockStr(); }
599
600private:
601 GlobalContext *const Ctx;
602};
603
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700604} // end of namespace Ice
605
606#endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H