blob: 4fd9592862b667234d77c5b6b8be8f107597c2f4 [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//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \brief Declares aspects of the compilation that persist across multiple
Andrew Scull57e12682015-09-16 11:30:19 -070012/// functions.
Andrew Scull9612d322015-07-06 14:53:25 -070013///
Jim Stichnothf7c9a142014-04-29 10:52:43 -070014//===----------------------------------------------------------------------===//
15
16#ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H
17#define SUBZERO_SRC_ICEGLOBALCONTEXT_H
18
Jim Stichnothf7c9a142014-04-29 10:52:43 -070019#include "IceDefs.h"
Karl Schimpf9d98d792014-10-13 15:01:08 -070020#include "IceClFlags.h"
Jan Voung3bd9f1a2014-06-18 10:50:57 -070021#include "IceIntrinsics.h"
Matt Wala1bd2fce2014-08-08 14:02:09 -070022#include "IceRNG.h"
Andrew Scull86df4e92015-07-30 13:54:44 -070023#include "IceSwitchLowering.h"
Jim Stichnothbbca7542015-02-11 16:08:31 -080024#include "IceThreading.h"
Jim Stichnoth8363a062014-10-07 10:02:38 -070025#include "IceTimerTree.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070026#include "IceTypes.h"
Jim Stichnothfa4efea2015-01-27 05:06:03 -080027#include "IceUtils.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070028
John Porto67f8de92015-06-25 10:14:17 -070029#include <array>
30#include <functional>
31#include <mutex>
32#include <thread>
33#include <type_traits>
34#include <vector>
35
Jim Stichnothf7c9a142014-04-29 10:52:43 -070036namespace Ice {
37
Jim Stichnoth989a7032014-08-08 10:13:44 -070038class ClFlags;
Jim Stichnothe4a8f402015-01-20 12:52:51 -080039class ConstantPool;
Jim Stichnothbbca7542015-02-11 16:08:31 -080040class EmitterWorkItem;
Karl Schimpf9d98d792014-10-13 15:01:08 -070041class FuncSigType;
Jim Stichnoth989a7032014-08-08 10:13:44 -070042
Andrew Scull9612d322015-07-06 14:53:25 -070043/// LockedPtr is a way to provide automatically locked access to some object.
Jim Stichnothe4a8f402015-01-20 12:52:51 -080044template <typename T> class LockedPtr {
45 LockedPtr() = delete;
46 LockedPtr(const LockedPtr &) = delete;
47 LockedPtr &operator=(const LockedPtr &) = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070048
Jim Stichnoth18735602014-09-16 19:59:35 -070049public:
Jim Stichnothe4a8f402015-01-20 12:52:51 -080050 LockedPtr(T *Value, GlobalLockType *Lock) : Value(Value), Lock(Lock) {
51 Lock->lock();
52 }
53 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) {
54 Other.Value = nullptr;
55 Other.Lock = nullptr;
56 }
57 ~LockedPtr() { Lock->unlock(); }
58 T *operator->() const { return Value; }
Andrew Scull86df4e92015-07-30 13:54:44 -070059 T &operator*() const { return *Value; }
Jim Stichnoth18735602014-09-16 19:59:35 -070060
61private:
Jim Stichnothe4a8f402015-01-20 12:52:51 -080062 T *Value;
63 GlobalLockType *Lock;
Jim Stichnoth18735602014-09-16 19:59:35 -070064};
65
Jim Stichnothf7c9a142014-04-29 10:52:43 -070066class GlobalContext {
Jim Stichnothc6ead202015-02-24 09:30:30 -080067 GlobalContext() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070068 GlobalContext(const GlobalContext &) = delete;
69 GlobalContext &operator=(const GlobalContext &) = delete;
70
Andrew Scull9612d322015-07-06 14:53:25 -070071 /// CodeStats collects rudimentary statistics during translation.
Jim Stichnothe4a8f402015-01-20 12:52:51 -080072 class CodeStats {
73 CodeStats(const CodeStats &) = delete;
74 CodeStats &operator=(const CodeStats &) = default;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080075#define CODESTATS_TABLE \
76 /* dump string, enum value */ \
77 X("Inst Count ", InstCount) \
78 X("Regs Saved ", RegsSaved) \
79 X("Frame Bytes ", FrameByte) \
80 X("Spills ", NumSpills) \
Qining Lu253dc8a2015-06-22 10:10:23 -070081 X("Fills ", NumFills) \
82 X("R/P Imms ", NumRPImms)
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080083 //#define X(str, tag)
Jim Stichnothe4a8f402015-01-20 12:52:51 -080084
85 public:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080086 enum CSTag {
87#define X(str, tag) CS_##tag,
88 CODESTATS_TABLE
89#undef X
90 CS_NUM
91 };
92 CodeStats() { reset(); }
93 void reset() { Stats.fill(0); }
94 void update(CSTag Tag, uint32_t Count = 1) {
95 assert(Tag < Stats.size());
96 Stats[Tag] += Count;
97 }
98 void add(const CodeStats &Other) {
99 for (uint32_t i = 0; i < Stats.size(); ++i)
100 Stats[i] += Other.Stats[i];
101 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800102 void dump(const IceString &Name, Ostream &Str);
103
104 private:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800105 std::array<uint32_t, CS_NUM> Stats;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800106 };
107
Andrew Scull9612d322015-07-06 14:53:25 -0700108 /// TimerList is a vector of TimerStack objects, with extra methods
109 /// to initialize and merge these vectors.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800110 class TimerList : public std::vector<TimerStack> {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800111 TimerList(const TimerList &) = delete;
112 TimerList &operator=(const TimerList &) = delete;
113
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800114 public:
Jim Stichnothc6ead202015-02-24 09:30:30 -0800115 TimerList() = default;
Andrew Scull9612d322015-07-06 14:53:25 -0700116 /// initInto() initializes a target list of timers based on the
117 /// current list. In particular, it creates the same number of
118 /// timers, in the same order, with the same names, but initially
119 /// empty of timing data.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800120 void initInto(TimerList &Dest) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700121 if (!BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800122 return;
123 Dest.clear();
124 for (const TimerStack &Stack : *this) {
125 Dest.push_back(TimerStack(Stack.getName()));
126 }
127 }
128 void mergeFrom(TimerList &Src) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700129 if (!BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800130 return;
131 assert(size() == Src.size());
132 size_type i = 0;
133 for (TimerStack &Stack : *this) {
134 assert(Stack.getName() == Src[i].getName());
135 Stack.mergeFrom(Src[i]);
136 ++i;
137 }
138 }
139 };
140
Andrew Scull9612d322015-07-06 14:53:25 -0700141 /// ThreadContext contains thread-local data. This data can be
142 /// combined/reduced as needed after all threads complete.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800143 class ThreadContext {
144 ThreadContext(const ThreadContext &) = delete;
145 ThreadContext &operator=(const ThreadContext &) = delete;
146
147 public:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700148 ThreadContext() = default;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800149 CodeStats StatsFunction;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800150 CodeStats StatsCumulative;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800151 TimerList Timers;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800152 };
153
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700154public:
Andrew Scull9612d322015-07-06 14:53:25 -0700155 /// The dump stream is a log stream while emit is the stream code
156 /// is emitted to. The error stream is strictly for logging errors.
Karl Schimpf2f67b922015-04-22 15:20:16 -0700157 GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
158 ELFStreamer *ELFStreamer, const ClFlags &Flags);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700159 ~GlobalContext();
160
Andrew Scull9612d322015-07-06 14:53:25 -0700161 ///
162 /// The dump, error, and emit streams need to be used by only one
163 /// thread at a time. This is done by exclusively reserving the
164 /// streams via lockStr() and unlockStr(). The OstreamLocker class
165 /// can be used to conveniently manage this.
166 ///
167 /// The model is that a thread grabs the stream lock, then does an
168 /// arbitrary amount of work during which far-away callees may grab
169 /// the stream and do something with it, and finally the thread
170 /// releases the stream lock. This allows large chunks of output to
171 /// be dumped or emitted without risking interleaving from multiple
172 /// threads.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800173 void lockStr() { StrLock.lock(); }
174 void unlockStr() { StrLock.unlock(); }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700175 Ostream &getStrDump() { return *StrDump; }
Karl Schimpf2f67b922015-04-22 15:20:16 -0700176 Ostream &getStrError() { return *StrError; }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700177 Ostream &getStrEmit() { return *StrEmit; }
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700178 void setStrEmit(Ostream &NewStrEmit) { StrEmit = &NewStrEmit; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700179
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800180 LockedPtr<ErrorCode> getErrorStatus() {
181 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock);
182 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700183
Andrew Scull9612d322015-07-06 14:53:25 -0700184 /// When emitting assembly, we allow a string to be prepended to
185 /// names of translated functions. This makes it easier to create an
186 /// execution test against a reference translator like llc, with both
187 /// translators using the same bitcode as input.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700188 IceString mangleName(const IceString &Name) const;
189
Andrew Scull57e12682015-09-16 11:30:19 -0700190 /// \name Manage Constants.
191 /// @{
192 // getConstant*() functions are not const because they might add something to
193 // the constant pool.
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800194 Constant *getConstantInt(Type Ty, int64_t Value);
195 Constant *getConstantInt1(int8_t ConstantInt1);
196 Constant *getConstantInt8(int8_t ConstantInt8);
197 Constant *getConstantInt16(int16_t ConstantInt16);
198 Constant *getConstantInt32(int32_t ConstantInt32);
199 Constant *getConstantInt64(int64_t ConstantInt64);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700200 Constant *getConstantFloat(float Value);
201 Constant *getConstantDouble(double Value);
Andrew Scull9612d322015-07-06 14:53:25 -0700202 /// Returns a symbolic constant.
John Portoe82b5602016-02-24 15:58:55 -0800203 Constant *getConstantSym(const RelocOffsetT Offset,
204 const RelocOffsetArray &OffsetExpr,
John Porto27fddcc2016-02-02 15:06:09 -0800205 const IceString &Name, const IceString &EmitString,
206 bool SuppressMangling);
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800207 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name,
208 bool SuppressMangling);
Jan Voung261cae32015-02-01 10:31:03 -0800209 Constant *getConstantExternSym(const IceString &Name);
Andrew Scull9612d322015-07-06 14:53:25 -0700210 /// Returns an undef.
Matt Walad8f4a7d2014-06-18 09:55:03 -0700211 Constant *getConstantUndef(Type Ty);
Andrew Scull9612d322015-07-06 14:53:25 -0700212 /// Returns a zero value.
Matt Walad8f4a7d2014-06-18 09:55:03 -0700213 Constant *getConstantZero(Type Ty);
Andrew Scull57e12682015-09-16 11:30:19 -0700214 /// getConstantPool() returns a copy of the constant pool for constants of a
215 /// given type.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800216 ConstantList getConstantPool(Type Ty);
Andrew Scull9612d322015-07-06 14:53:25 -0700217 /// Returns a copy of the list of external symbols.
Jan Voung261cae32015-02-01 10:31:03 -0800218 ConstantList getConstantExternSyms();
Andrew Scull57e12682015-09-16 11:30:19 -0700219 /// @}
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700220
Andrew Scull86df4e92015-07-30 13:54:44 -0700221 /// Return a locked pointer to the registered jump tables.
Andrew Scull1eda90a2015-08-04 17:03:19 -0700222 JumpTableDataList getJumpTables();
Andrew Scull86df4e92015-07-30 13:54:44 -0700223 /// Create a new jump table entry and return a reference to it.
David Sehr0fe6b542015-11-19 21:47:15 -0800224 JumpTableData &addJumpTable(IceString FuncName, SizeT Id,
225 const JumpTableData::TargetList &TargetList);
Andrew Scull86df4e92015-07-30 13:54:44 -0700226
Jim Stichnoth989a7032014-08-08 10:13:44 -0700227 const ClFlags &getFlags() const { return Flags; }
228
Andrew Scull9612d322015-07-06 14:53:25 -0700229 /// Allocate data of type T using the global allocator. We allow entities
230 /// allocated from this global allocator to be either trivially or
231 /// non-trivially destructible. We optimize the case when T is trivially
232 /// destructible by not registering a destructor. Destructors will be invoked
233 /// during GlobalContext destruction in the reverse object creation order.
John Porto1bec8bc2015-06-22 10:51:13 -0700234 template <typename T>
235 typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type *
236 allocate() {
237 return getAllocator()->Allocate<T>();
238 }
239
240 template <typename T>
241 typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type *
242 allocate() {
243 T *Ret = getAllocator()->Allocate<T>();
244 getDestructors()->emplace_back([Ret]() { Ret->~T(); });
245 return Ret;
246 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700247
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700248 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
249
Jan Voung08c3bcd2014-12-01 17:55:16 -0800250 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); }
251
Andrew Scull9612d322015-07-06 14:53:25 -0700252 /// Reset stats at the beginning of a function.
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800253 void resetStats() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700254 if (BuildDefs::dump())
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800255 ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset();
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800256 }
Jim Stichnothff9c7062014-09-18 04:50:49 -0700257 void dumpStats(const IceString &Name, bool Final = false);
Jim Stichnoth18735602014-09-16 19:59:35 -0700258 void statsUpdateEmitted(uint32_t InstCount) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800259 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800260 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700261 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
262 Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount);
263 Tls->StatsCumulative.update(CodeStats::CS_InstCount, InstCount);
Jim Stichnoth18735602014-09-16 19:59:35 -0700264 }
265 void statsUpdateRegistersSaved(uint32_t Num) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800266 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800267 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700268 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
269 Tls->StatsFunction.update(CodeStats::CS_RegsSaved, Num);
270 Tls->StatsCumulative.update(CodeStats::CS_RegsSaved, Num);
Jim Stichnoth18735602014-09-16 19:59:35 -0700271 }
272 void statsUpdateFrameBytes(uint32_t Bytes) {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800273 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800274 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700275 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
276 Tls->StatsFunction.update(CodeStats::CS_FrameByte, Bytes);
277 Tls->StatsCumulative.update(CodeStats::CS_FrameByte, Bytes);
Jim Stichnoth18735602014-09-16 19:59:35 -0700278 }
279 void statsUpdateSpills() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800280 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800281 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700282 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
283 Tls->StatsFunction.update(CodeStats::CS_NumSpills);
284 Tls->StatsCumulative.update(CodeStats::CS_NumSpills);
Jim Stichnoth18735602014-09-16 19:59:35 -0700285 }
286 void statsUpdateFills() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800287 if (!getFlags().getDumpStats())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800288 return;
Jan Voung3e5009f2015-03-24 09:04:13 -0700289 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
290 Tls->StatsFunction.update(CodeStats::CS_NumFills);
291 Tls->StatsCumulative.update(CodeStats::CS_NumFills);
Jim Stichnoth18735602014-09-16 19:59:35 -0700292 }
293
Andrew Scull9612d322015-07-06 14:53:25 -0700294 /// Number of Randomized or Pooled Immediates
Qining Lu253dc8a2015-06-22 10:10:23 -0700295 void statsUpdateRPImms() {
296 if (!getFlags().getDumpStats())
297 return;
298 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
299 Tls->StatsFunction.update(CodeStats::CS_NumRPImms);
300 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms);
301 }
302
Andrew Scull9612d322015-07-06 14:53:25 -0700303 /// These are predefined TimerStackIdT values.
Jim Stichnothdd842db2015-01-27 12:53:53 -0800304 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num };
Jim Stichnoth8363a062014-10-07 10:02:38 -0700305
Andrew Scull57e12682015-09-16 11:30:19 -0700306 /// newTimerStackID() creates a new TimerStack in the global space. It does
307 /// not affect any TimerStack objects in TLS.
Jim Stichnoth8363a062014-10-07 10:02:38 -0700308 TimerStackIdT newTimerStackID(const IceString &Name);
Andrew Scull57e12682015-09-16 11:30:19 -0700309 /// dumpTimers() dumps the global timer data. As such, one probably wants to
310 /// call mergeTimerStacks() as a prerequisite.
Jim Stichnoth8363a062014-10-07 10:02:38 -0700311 void dumpTimers(TimerStackIdT StackID = TSK_Default,
312 bool DumpCumulative = true);
Andrew Scull57e12682015-09-16 11:30:19 -0700313 /// The following methods affect only the calling thread's TLS timer data.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800314 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name);
315 void pushTimer(TimerIdT ID, TimerStackIdT StackID);
316 void popTimer(TimerIdT ID, TimerStackIdT StackID);
317 void resetTimer(TimerStackIdT StackID);
318 void setTimerName(TimerStackIdT StackID, const IceString &NewName);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700319
Andrew Scull57e12682015-09-16 11:30:19 -0700320 /// This is the first work item sequence number that the parser produces, and
321 /// correspondingly the first sequence number that the emitter thread will
322 /// wait for. Start numbering at 1 to leave room for a sentinel, in case e.g.
323 /// we wish to inject items with a special sequence number that may be
324 /// executed out of order.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800325 static uint32_t getFirstSequenceNumber() { return 1; }
Andrew Scull57e12682015-09-16 11:30:19 -0700326 /// Adds a newly parsed and constructed function to the Cfg work queue.
327 /// Notifies any idle workers that a new function is available for
328 /// translating. May block if the work queue is too large, in order to control
329 /// memory footprint.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800330 void optQueueBlockingPush(std::unique_ptr<Cfg> Func);
Andrew Scull57e12682015-09-16 11:30:19 -0700331 /// Takes a Cfg from the work queue for translating. May block if the work
332 /// queue is currently empty. Returns nullptr if there is no more work - the
333 /// queue is empty and either end() has been called or the Sequential flag was
334 /// set.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800335 std::unique_ptr<Cfg> optQueueBlockingPop();
Andrew Scull9612d322015-07-06 14:53:25 -0700336 /// Notifies that no more work will be added to the work queue.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800337 void optQueueNotifyEnd() { OptQ.notifyEnd(); }
338
Andrew Scull9612d322015-07-06 14:53:25 -0700339 /// Emit file header for output file.
Jan Voungfb792842015-06-11 15:27:50 -0700340 void emitFileHeader();
341
John Porto8b1a7052015-06-17 13:20:08 -0700342 void lowerConstants();
343
Andrew Scull86df4e92015-07-30 13:54:44 -0700344 void lowerJumpTables();
345
Jim Stichnothbbca7542015-02-11 16:08:31 -0800346 void emitQueueBlockingPush(EmitterWorkItem *Item);
347 EmitterWorkItem *emitQueueBlockingPop();
348 void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800349
Jan Voung44c3a802015-03-27 16:29:08 -0700350 void initParserThread() {
351 ThreadContext *Tls = new ThreadContext();
352 auto Timers = getTimers();
353 Timers->initInto(Tls->Timers);
354 AllThreadContexts.push_back(Tls);
355 ICE_TLS_SET_FIELD(TLS, Tls);
356 }
357
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800358 void startWorkerThreads() {
Karl Schimpfdf80eb82015-02-09 14:20:22 -0800359 size_t NumWorkers = getFlags().getNumTranslationThreads();
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800360 auto Timers = getTimers();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800361 for (size_t i = 0; i < NumWorkers; ++i) {
362 ThreadContext *WorkerTLS = new ThreadContext();
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800363 Timers->initInto(WorkerTLS->Timers);
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800364 AllThreadContexts.push_back(WorkerTLS);
365 TranslationThreads.push_back(std::thread(
366 &GlobalContext::translateFunctionsWrapper, this, WorkerTLS));
367 }
368 if (NumWorkers) {
Jim Stichnothbbca7542015-02-11 16:08:31 -0800369 ThreadContext *WorkerTLS = new ThreadContext();
370 Timers->initInto(WorkerTLS->Timers);
371 AllThreadContexts.push_back(WorkerTLS);
372 EmitterThreads.push_back(
373 std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS));
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800374 }
375 }
376
377 void waitForWorkerThreads() {
Jim Stichnothbbca7542015-02-11 16:08:31 -0800378 optQueueNotifyEnd();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800379 for (std::thread &Worker : TranslationThreads) {
380 Worker.join();
381 }
382 TranslationThreads.clear();
Jim Stichnothbbca7542015-02-11 16:08:31 -0800383
Andrew Scull57e12682015-09-16 11:30:19 -0700384 // Only notify the emit queue to end after all the translation threads have
385 // ended.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800386 emitQueueNotifyEnd();
387 for (std::thread &Worker : EmitterThreads) {
388 Worker.join();
389 }
390 EmitterThreads.clear();
391
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700392 if (BuildDefs::dump()) {
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800393 auto Timers = getTimers();
394 for (ThreadContext *TLS : AllThreadContexts)
395 Timers->mergeFrom(TLS->Timers);
396 }
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700397 if (BuildDefs::dump()) {
Andrew Scull57e12682015-09-16 11:30:19 -0700398 // Do a separate loop over AllThreadContexts to avoid holding two locks
399 // at once.
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800400 auto Stats = getStatsCumulative();
401 for (ThreadContext *TLS : AllThreadContexts)
402 Stats->add(TLS->StatsCumulative);
403 }
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800404 }
405
Andrew Scull9612d322015-07-06 14:53:25 -0700406 /// Translation thread startup routine.
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800407 void translateFunctionsWrapper(ThreadContext *MyTLS) {
408 ICE_TLS_SET_FIELD(TLS, MyTLS);
409 translateFunctions();
410 }
Andrew Scull9612d322015-07-06 14:53:25 -0700411 /// Translate functions from the Cfg queue until the queue is empty.
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800412 void translateFunctions();
413
Andrew Scull9612d322015-07-06 14:53:25 -0700414 /// Emitter thread startup routine.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800415 void emitterWrapper(ThreadContext *MyTLS) {
416 ICE_TLS_SET_FIELD(TLS, MyTLS);
417 emitItems();
418 }
Andrew Scull57e12682015-09-16 11:30:19 -0700419 /// Emit functions and global initializers from the emitter queue until the
420 /// queue is empty.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800421 void emitItems();
422
Andrew Scull9612d322015-07-06 14:53:25 -0700423 /// Uses DataLowering to lower Globals. Side effects:
424 /// - discards the initializer list for the global variable in Globals.
425 /// - clears the Globals array.
John Porto8b1a7052015-06-17 13:20:08 -0700426 void lowerGlobals(const IceString &SectionSuffix);
427
Andrew Scull9612d322015-07-06 14:53:25 -0700428 /// Lowers the profile information.
John Porto8b1a7052015-06-17 13:20:08 -0700429 void lowerProfileData();
430
Andrew Scull57e12682015-09-16 11:30:19 -0700431 /// Utility function to match a symbol name against a match string. This is
432 /// used in a few cases where we want to take some action on a particular
433 /// function or symbol based on a command-line argument, such as changing the
434 /// verbose level for a particular function. An empty Match argument means
435 /// match everything. Returns true if there is a match.
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800436 static bool matchSymbolName(const IceString &SymbolName,
437 const IceString &Match) {
438 return Match.empty() || Match == SymbolName;
439 }
440
441private:
442 // Try to ensure mutexes are allocated on separate cache lines.
443
John Porto1bec8bc2015-06-22 10:51:13 -0700444 // Destructors collaborate with Allocator
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800445 ICE_CACHELINE_BOUNDARY;
446 // Managed by getAllocator()
447 GlobalLockType AllocLock;
John Portoe82b5602016-02-24 15:58:55 -0800448 ArenaAllocator Allocator;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800449
450 ICE_CACHELINE_BOUNDARY;
John Porto1bec8bc2015-06-22 10:51:13 -0700451 // Managed by getDestructors()
Andrew Scull8072bae2015-09-14 16:01:26 -0700452 using DestructorArray = std::vector<std::function<void()>>;
John Porto1bec8bc2015-06-22 10:51:13 -0700453 GlobalLockType DestructorsLock;
454 DestructorArray Destructors;
455
456 ICE_CACHELINE_BOUNDARY;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800457 // Managed by getConstantPool()
458 GlobalLockType ConstPoolLock;
459 std::unique_ptr<ConstantPool> ConstPool;
460
461 ICE_CACHELINE_BOUNDARY;
Andrew Scull1eda90a2015-08-04 17:03:19 -0700462 // Managed by getJumpTableList()
Andrew Scull86df4e92015-07-30 13:54:44 -0700463 GlobalLockType JumpTablesLock;
Andrew Scull1eda90a2015-08-04 17:03:19 -0700464 JumpTableDataList JumpTableList;
Andrew Scull86df4e92015-07-30 13:54:44 -0700465
466 ICE_CACHELINE_BOUNDARY;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800467 // Managed by getErrorStatus()
468 GlobalLockType ErrorStatusLock;
469 ErrorCode ErrorStatus;
470
471 ICE_CACHELINE_BOUNDARY;
472 // Managed by getStatsCumulative()
473 GlobalLockType StatsLock;
474 CodeStats StatsCumulative;
475
476 ICE_CACHELINE_BOUNDARY;
477 // Managed by getTimers()
478 GlobalLockType TimerLock;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800479 TimerList Timers;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800480
481 ICE_CACHELINE_BOUNDARY;
Andrew Scull9612d322015-07-06 14:53:25 -0700482 /// StrLock is a global lock on the dump and emit output streams.
Andrew Scull8072bae2015-09-14 16:01:26 -0700483 using StrLockType = std::mutex;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800484 StrLockType StrLock;
Andrew Scull9612d322015-07-06 14:53:25 -0700485 Ostream *StrDump; /// Stream for dumping / diagnostics
486 Ostream *StrEmit; /// Stream for code emission
487 Ostream *StrError; /// Stream for logging errors.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700488
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800489 ICE_CACHELINE_BOUNDARY;
490
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700491 Intrinsics IntrinsicsInfo;
Jim Stichnoth989a7032014-08-08 10:13:44 -0700492 const ClFlags &Flags;
John Porto8b1a7052015-06-17 13:20:08 -0700493 // TODO(jpp): move to EmitterContext.
Jan Voung08c3bcd2014-12-01 17:55:16 -0800494 std::unique_ptr<ELFObjectWriter> ObjectWriter;
Jim Stichnothbbca7542015-02-11 16:08:31 -0800495 BoundedProducerConsumerQueue<Cfg> OptQ;
496 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ;
John Porto8b1a7052015-06-17 13:20:08 -0700497 // DataLowering is only ever used by a single thread at a time (either in
498 // emitItems(), or in IceCompiler::run before the compilation is over.)
499 // TODO(jpp): move to EmitterContext.
500 std::unique_ptr<TargetDataLowering> DataLowering;
Andrew Scull9612d322015-07-06 14:53:25 -0700501 /// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true"
502 /// program global variables) until the first code WorkItem is seen.
John Porto8b1a7052015-06-17 13:20:08 -0700503 // TODO(jpp): move to EmitterContext.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700504 bool HasSeenCode = false;
John Porto8b1a7052015-06-17 13:20:08 -0700505 // TODO(jpp): move to EmitterContext.
506 VariableDeclarationList Globals;
507 // TODO(jpp): move to EmitterContext.
John Porto1bec8bc2015-06-22 10:51:13 -0700508 VariableDeclaration *ProfileBlockInfoVarDecl;
Jim Stichnoth217dc082014-07-11 14:06:55 -0700509
John Portoe82b5602016-02-24 15:58:55 -0800510 LockedPtr<ArenaAllocator> getAllocator() {
511 return LockedPtr<ArenaAllocator>(&Allocator, &AllocLock);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800512 }
513 LockedPtr<ConstantPool> getConstPool() {
514 return LockedPtr<ConstantPool>(ConstPool.get(), &ConstPoolLock);
515 }
Andrew Scull1eda90a2015-08-04 17:03:19 -0700516 LockedPtr<JumpTableDataList> getJumpTableList() {
517 return LockedPtr<JumpTableDataList>(&JumpTableList, &JumpTablesLock);
518 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800519 LockedPtr<CodeStats> getStatsCumulative() {
520 return LockedPtr<CodeStats>(&StatsCumulative, &StatsLock);
521 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800522 LockedPtr<TimerList> getTimers() {
523 return LockedPtr<TimerList>(&Timers, &TimerLock);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800524 }
John Porto1bec8bc2015-06-22 10:51:13 -0700525 LockedPtr<DestructorArray> getDestructors() {
526 return LockedPtr<DestructorArray>(&Destructors, &DestructorsLock);
527 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800528
John Porto8b1a7052015-06-17 13:20:08 -0700529 void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
530 if (Globls != nullptr)
531 Globals.insert(Globals.end(), Globls->begin(), Globls->end());
532 }
533
534 void lowerGlobalsIfNoCodeHasBeenSeen() {
535 if (HasSeenCode)
536 return;
537 constexpr char NoSuffix[] = "";
538 lowerGlobals(NoSuffix);
539 HasSeenCode = true;
540 }
541
John Porto844211e2016-02-04 08:42:48 -0800542 void addBlockInfoPtrs(VariableDeclaration *ProfileBlockInfo);
543
Jim Stichnothbbca7542015-02-11 16:08:31 -0800544 llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
545 llvm::SmallVector<std::thread, 128> TranslationThreads;
546 llvm::SmallVector<std::thread, 128> EmitterThreads;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800547 // Each thread has its own TLS pointer which is also held in
548 // AllThreadContexts.
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800549 ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800550
Jim Stichnoth217dc082014-07-11 14:06:55 -0700551 // Private helpers for mangleName()
Andrew Scull8072bae2015-09-14 16:01:26 -0700552 using ManglerVector = llvm::SmallVector<char, 32>;
Jim Stichnoth217dc082014-07-11 14:06:55 -0700553 void incrementSubstitutions(ManglerVector &OldName) const;
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800554
555public:
556 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700557};
558
Andrew Scull57e12682015-09-16 11:30:19 -0700559/// Helper class to push and pop a timer marker. The constructor pushes a
560/// marker, and the destructor pops it. This is for convenient timing of regions
561/// of code.
Jim Stichnothc4554d72014-09-30 16:49:38 -0700562class TimerMarker {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800563 TimerMarker() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700564 TimerMarker(const TimerMarker &) = delete;
565 TimerMarker &operator=(const TimerMarker &) = delete;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700566
567public:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800568 TimerMarker(TimerIdT ID, GlobalContext *Ctx,
569 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700570 : ID(ID), Ctx(Ctx), StackID(StackID) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700571 if (BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800572 push();
Jim Stichnothc4554d72014-09-30 16:49:38 -0700573 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800574 TimerMarker(TimerIdT ID, const Cfg *Func,
575 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700576 : ID(ID), Ctx(nullptr), StackID(StackID) {
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800577 // Ctx gets set at the beginning of pushCfg().
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700578 if (BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800579 pushCfg(Func);
580 }
Jim Stichnoth8363a062014-10-07 10:02:38 -0700581
Jim Stichnothc4554d72014-09-30 16:49:38 -0700582 ~TimerMarker() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700583 if (BuildDefs::dump() && Active)
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800584 Ctx->popTimer(ID, StackID);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700585 }
586
587private:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800588 void push();
589 void pushCfg(const Cfg *Func);
590 const TimerIdT ID;
591 GlobalContext *Ctx;
592 const TimerStackIdT StackID;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700593 bool Active = false;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700594};
595
Andrew Scull57e12682015-09-16 11:30:19 -0700596/// Helper class for locking the streams and then automatically unlocking them.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800597class OstreamLocker {
598private:
599 OstreamLocker() = delete;
600 OstreamLocker(const OstreamLocker &) = delete;
601 OstreamLocker &operator=(const OstreamLocker &) = delete;
602
603public:
604 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); }
605 ~OstreamLocker() { Ctx->unlockStr(); }
606
607private:
608 GlobalContext *const Ctx;
609};
610
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700611} // end of namespace Ice
612
613#endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H