blob: 55b37d813e220b7d6180e34a3ae8528a770063e4 [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"
Thomas Livelyaab70992016-06-07 13:54:59 -070021#include "IceInstrumentation.h"
Jan Voung3bd9f1a2014-06-18 10:50:57 -070022#include "IceIntrinsics.h"
Matt Wala1bd2fce2014-08-08 14:02:09 -070023#include "IceRNG.h"
Jim Stichnoth467ffe52016-03-29 15:01:06 -070024#include "IceStringPool.h"
Andrew Scull86df4e92015-07-30 13:54:44 -070025#include "IceSwitchLowering.h"
Karl Schimpf20070e82016-03-17 13:30:13 -070026#include "IceTargetLowering.def"
Jim Stichnothbbca7542015-02-11 16:08:31 -080027#include "IceThreading.h"
Jim Stichnoth8363a062014-10-07 10:02:38 -070028#include "IceTimerTree.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070029#include "IceTypes.h"
Jim Stichnothfa4efea2015-01-27 05:06:03 -080030#include "IceUtils.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070031
John Porto67f8de92015-06-25 10:14:17 -070032#include <array>
Karl Schimpfe8457a22016-03-31 10:20:23 -070033#include <atomic>
Karl Schimpf20070e82016-03-17 13:30:13 -070034#include <cassert>
John Porto67f8de92015-06-25 10:14:17 -070035#include <functional>
John Portobd2e2312016-03-15 11:06:25 -070036#include <memory>
John Porto67f8de92015-06-25 10:14:17 -070037#include <mutex>
38#include <thread>
39#include <type_traits>
John Portobd2e2312016-03-15 11:06:25 -070040#include <utility>
John Porto67f8de92015-06-25 10:14:17 -070041#include <vector>
42
Jim Stichnothf7c9a142014-04-29 10:52:43 -070043namespace Ice {
44
Jim Stichnothe4a8f402015-01-20 12:52:51 -080045class ConstantPool;
Jim Stichnothbbca7542015-02-11 16:08:31 -080046class EmitterWorkItem;
Karl Schimpf9d98d792014-10-13 15:01:08 -070047class FuncSigType;
Thomas Livelyaab70992016-06-07 13:54:59 -070048class Instrumentation;
Jim Stichnoth989a7032014-08-08 10:13:44 -070049
Karl Schimpf20070e82016-03-17 13:30:13 -070050// Runtime helper function IDs
51
52enum class RuntimeHelper {
53#define X(Tag, Name) H_##Tag,
54 RUNTIME_HELPER_FUNCTIONS_TABLE
55#undef X
56 H_Num
57};
58
Karl Schimpfe8457a22016-03-31 10:20:23 -070059/// OptWorkItem is a simple wrapper used to pass parse information on a function
60/// block, to a translator thread.
61class OptWorkItem {
62 OptWorkItem(const OptWorkItem &) = delete;
63 OptWorkItem &operator=(const OptWorkItem &) = delete;
64
65public:
66 // Get the Cfg for the funtion to translate.
67 virtual std::unique_ptr<Cfg> getParsedCfg() = 0;
68 virtual ~OptWorkItem() = default;
69
70protected:
71 OptWorkItem() = default;
72};
73
Jim Stichnothf7c9a142014-04-29 10:52:43 -070074class GlobalContext {
Jim Stichnothc6ead202015-02-24 09:30:30 -080075 GlobalContext() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070076 GlobalContext(const GlobalContext &) = delete;
77 GlobalContext &operator=(const GlobalContext &) = delete;
78
Andrew Scull9612d322015-07-06 14:53:25 -070079 /// CodeStats collects rudimentary statistics during translation.
Jim Stichnothe4a8f402015-01-20 12:52:51 -080080 class CodeStats {
81 CodeStats(const CodeStats &) = delete;
82 CodeStats &operator=(const CodeStats &) = default;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080083#define CODESTATS_TABLE \
84 /* dump string, enum value */ \
85 X("Inst Count ", InstCount) \
86 X("Regs Saved ", RegsSaved) \
87 X("Frame Bytes ", FrameByte) \
88 X("Spills ", NumSpills) \
Qining Lu253dc8a2015-06-22 10:10:23 -070089 X("Fills ", NumFills) \
90 X("R/P Imms ", NumRPImms)
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080091 //#define X(str, tag)
Jim Stichnothe4a8f402015-01-20 12:52:51 -080092
93 public:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -080094 enum CSTag {
95#define X(str, tag) CS_##tag,
96 CODESTATS_TABLE
97#undef X
98 CS_NUM
99 };
100 CodeStats() { reset(); }
101 void reset() { Stats.fill(0); }
102 void update(CSTag Tag, uint32_t Count = 1) {
103 assert(Tag < Stats.size());
104 Stats[Tag] += Count;
105 }
106 void add(const CodeStats &Other) {
107 for (uint32_t i = 0; i < Stats.size(); ++i)
108 Stats[i] += Other.Stats[i];
109 }
Jim Stichnothb5eee3d2016-03-31 11:05:39 -0700110 /// Dumps the stats for the given Cfg. If Func==nullptr, it identifies it
111 /// as the "final" cumulative stats instead as a specific function's name.
112 void dump(const Cfg *Func, GlobalContext *Ctx);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800113
114 private:
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800115 std::array<uint32_t, CS_NUM> Stats;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800116 };
117
Andrew Scull9612d322015-07-06 14:53:25 -0700118 /// TimerList is a vector of TimerStack objects, with extra methods
119 /// to initialize and merge these vectors.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800120 class TimerList : public std::vector<TimerStack> {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800121 TimerList(const TimerList &) = delete;
122 TimerList &operator=(const TimerList &) = delete;
123
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800124 public:
Jim Stichnothc6ead202015-02-24 09:30:30 -0800125 TimerList() = default;
Andrew Scull9612d322015-07-06 14:53:25 -0700126 /// initInto() initializes a target list of timers based on the
127 /// current list. In particular, it creates the same number of
128 /// timers, in the same order, with the same names, but initially
129 /// empty of timing data.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800130 void initInto(TimerList &Dest) const {
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800131 if (!BuildDefs::timers())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800132 return;
133 Dest.clear();
134 for (const TimerStack &Stack : *this) {
135 Dest.push_back(TimerStack(Stack.getName()));
136 }
137 }
138 void mergeFrom(TimerList &Src) {
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800139 if (!BuildDefs::timers())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800140 return;
141 assert(size() == Src.size());
142 size_type i = 0;
143 for (TimerStack &Stack : *this) {
144 assert(Stack.getName() == Src[i].getName());
145 Stack.mergeFrom(Src[i]);
146 ++i;
147 }
148 }
149 };
150
Andrew Scull9612d322015-07-06 14:53:25 -0700151 /// ThreadContext contains thread-local data. This data can be
152 /// combined/reduced as needed after all threads complete.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800153 class ThreadContext {
154 ThreadContext(const ThreadContext &) = delete;
155 ThreadContext &operator=(const ThreadContext &) = delete;
156
157 public:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700158 ThreadContext() = default;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800159 CodeStats StatsFunction;
Jim Stichnotha1dd3cc2015-01-31 10:48:11 -0800160 CodeStats StatsCumulative;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800161 TimerList Timers;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800162 };
163
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700164public:
Andrew Scull9612d322015-07-06 14:53:25 -0700165 /// The dump stream is a log stream while emit is the stream code
166 /// is emitted to. The error stream is strictly for logging errors.
Karl Schimpf2f67b922015-04-22 15:20:16 -0700167 GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800168 ELFStreamer *ELFStreamer);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700169 ~GlobalContext();
170
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700171 void dumpStrings();
Andrew Scull9612d322015-07-06 14:53:25 -0700172 ///
173 /// The dump, error, and emit streams need to be used by only one
174 /// thread at a time. This is done by exclusively reserving the
175 /// streams via lockStr() and unlockStr(). The OstreamLocker class
176 /// can be used to conveniently manage this.
177 ///
178 /// The model is that a thread grabs the stream lock, then does an
179 /// arbitrary amount of work during which far-away callees may grab
180 /// the stream and do something with it, and finally the thread
181 /// releases the stream lock. This allows large chunks of output to
182 /// be dumped or emitted without risking interleaving from multiple
183 /// threads.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800184 void lockStr() { StrLock.lock(); }
185 void unlockStr() { StrLock.unlock(); }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700186 Ostream &getStrDump() { return *StrDump; }
Karl Schimpf2f67b922015-04-22 15:20:16 -0700187 Ostream &getStrError() { return *StrError; }
Jim Stichnoth78282f62014-07-27 23:14:00 -0700188 Ostream &getStrEmit() { return *StrEmit; }
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700189 void setStrEmit(Ostream &NewStrEmit) { StrEmit = &NewStrEmit; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700190
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800191 LockedPtr<ErrorCode> getErrorStatus() {
192 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock);
193 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700194
Andrew Scull57e12682015-09-16 11:30:19 -0700195 /// \name Manage Constants.
196 /// @{
197 // getConstant*() functions are not const because they might add something to
198 // the constant pool.
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800199 Constant *getConstantInt(Type Ty, int64_t Value);
Karl Schimpf20070e82016-03-17 13:30:13 -0700200 Constant *getConstantInt1(int8_t ConstantInt1) {
201 ConstantInt1 &= INT8_C(1);
202 switch (ConstantInt1) {
203 case 0:
204 return getConstantZero(IceType_i1);
205 case 1:
206 return ConstantTrue;
207 default:
208 assert(false && "getConstantInt1 not on true/false");
209 return getConstantInt1Internal(ConstantInt1);
210 }
211 }
212 Constant *getConstantInt8(int8_t ConstantInt8) {
213 switch (ConstantInt8) {
214 case 0:
215 return getConstantZero(IceType_i8);
216 default:
217 return getConstantInt8Internal(ConstantInt8);
218 }
219 }
220 Constant *getConstantInt16(int16_t ConstantInt16) {
221 switch (ConstantInt16) {
222 case 0:
223 return getConstantZero(IceType_i16);
224 default:
225 return getConstantInt16Internal(ConstantInt16);
226 }
227 }
228 Constant *getConstantInt32(int32_t ConstantInt32) {
229 switch (ConstantInt32) {
230 case 0:
231 return getConstantZero(IceType_i32);
232 default:
233 return getConstantInt32Internal(ConstantInt32);
234 }
235 }
236 Constant *getConstantInt64(int64_t ConstantInt64) {
237 switch (ConstantInt64) {
238 case 0:
239 return getConstantZero(IceType_i64);
240 default:
241 return getConstantInt64Internal(ConstantInt64);
242 }
243 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700244 Constant *getConstantFloat(float Value);
245 Constant *getConstantDouble(double Value);
Andrew Scull9612d322015-07-06 14:53:25 -0700246 /// Returns a symbolic constant.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700247 Constant *getConstantSymWithEmitString(const RelocOffsetT Offset,
248 const RelocOffsetArray &OffsetExpr,
249 GlobalString Name,
250 const std::string &EmitString);
251 Constant *getConstantSym(RelocOffsetT Offset, GlobalString Name);
252 Constant *getConstantExternSym(GlobalString Name);
Andrew Scull9612d322015-07-06 14:53:25 -0700253 /// Returns an undef.
Matt Walad8f4a7d2014-06-18 09:55:03 -0700254 Constant *getConstantUndef(Type Ty);
Andrew Scull9612d322015-07-06 14:53:25 -0700255 /// Returns a zero value.
Matt Walad8f4a7d2014-06-18 09:55:03 -0700256 Constant *getConstantZero(Type Ty);
Andrew Scull57e12682015-09-16 11:30:19 -0700257 /// getConstantPool() returns a copy of the constant pool for constants of a
258 /// given type.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800259 ConstantList getConstantPool(Type Ty);
Andrew Scull9612d322015-07-06 14:53:25 -0700260 /// Returns a copy of the list of external symbols.
Jan Voung261cae32015-02-01 10:31:03 -0800261 ConstantList getConstantExternSyms();
Andrew Scull57e12682015-09-16 11:30:19 -0700262 /// @}
Karl Schimpf20070e82016-03-17 13:30:13 -0700263 Constant *getRuntimeHelperFunc(RuntimeHelper FuncID) const {
264 assert(FuncID < RuntimeHelper::H_Num);
265 Constant *Result = RuntimeHelperFunc[static_cast<size_t>(FuncID)];
266 assert(Result != nullptr && "No such runtime helper function");
267 return Result;
268 }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700269 GlobalString getGlobalString(const std::string &Name);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700270
Andrew Scull86df4e92015-07-30 13:54:44 -0700271 /// Return a locked pointer to the registered jump tables.
Andrew Scull1eda90a2015-08-04 17:03:19 -0700272 JumpTableDataList getJumpTables();
John Porto03077212016-04-05 06:30:21 -0700273 /// Adds JumpTable to the list of know jump tables, for a posteriori emission.
274 void addJumpTableData(JumpTableData JumpTable);
Andrew Scull86df4e92015-07-30 13:54:44 -0700275
Andrew Scull9612d322015-07-06 14:53:25 -0700276 /// Allocate data of type T using the global allocator. We allow entities
277 /// allocated from this global allocator to be either trivially or
278 /// non-trivially destructible. We optimize the case when T is trivially
279 /// destructible by not registering a destructor. Destructors will be invoked
280 /// during GlobalContext destruction in the reverse object creation order.
John Porto1bec8bc2015-06-22 10:51:13 -0700281 template <typename T>
282 typename std::enable_if<std::is_trivially_destructible<T>::value, T>::type *
283 allocate() {
284 return getAllocator()->Allocate<T>();
285 }
286
287 template <typename T>
288 typename std::enable_if<!std::is_trivially_destructible<T>::value, T>::type *
289 allocate() {
290 T *Ret = getAllocator()->Allocate<T>();
291 getDestructors()->emplace_back([Ret]() { Ret->~T(); });
292 return Ret;
293 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700294
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700295 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
296
Jan Voung08c3bcd2014-12-01 17:55:16 -0800297 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); }
298
Andrew Scull9612d322015-07-06 14:53:25 -0700299 /// Reset stats at the beginning of a function.
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700300 void resetStats();
Jim Stichnothb5eee3d2016-03-31 11:05:39 -0700301 void dumpStats(const Cfg *Func = nullptr);
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700302 void statsUpdateEmitted(uint32_t InstCount);
303 void statsUpdateRegistersSaved(uint32_t Num);
304 void statsUpdateFrameBytes(uint32_t Bytes);
305 void statsUpdateSpills();
306 void statsUpdateFills();
Jim Stichnoth18735602014-09-16 19:59:35 -0700307
Andrew Scull9612d322015-07-06 14:53:25 -0700308 /// Number of Randomized or Pooled Immediates
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700309 void statsUpdateRPImms();
Qining Lu253dc8a2015-06-22 10:10:23 -0700310
Andrew Scull9612d322015-07-06 14:53:25 -0700311 /// These are predefined TimerStackIdT values.
Jim Stichnothdd842db2015-01-27 12:53:53 -0800312 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num };
Jim Stichnoth8363a062014-10-07 10:02:38 -0700313
Andrew Scull57e12682015-09-16 11:30:19 -0700314 /// newTimerStackID() creates a new TimerStack in the global space. It does
315 /// not affect any TimerStack objects in TLS.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700316 TimerStackIdT newTimerStackID(const std::string &Name);
Jim Stichnoth318c01b2016-04-03 21:58:03 -0700317 /// dumpTimers() dumps the global timer data. This assumes all the
318 /// thread-local copies of timer data have been merged into the global timer
319 /// data.
Jim Stichnoth8363a062014-10-07 10:02:38 -0700320 void dumpTimers(TimerStackIdT StackID = TSK_Default,
321 bool DumpCumulative = true);
Jim Stichnoth2b000fd2016-04-06 06:37:15 -0700322 void dumpLocalTimers(const std::string &TimerNameOverride,
323 TimerStackIdT StackID = TSK_Default,
324 bool DumpCumulative = true);
Andrew Scull57e12682015-09-16 11:30:19 -0700325 /// The following methods affect only the calling thread's TLS timer data.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700326 TimerIdT getTimerID(TimerStackIdT StackID, const std::string &Name);
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800327 void pushTimer(TimerIdT ID, TimerStackIdT StackID);
328 void popTimer(TimerIdT ID, TimerStackIdT StackID);
329 void resetTimer(TimerStackIdT StackID);
Jim Stichnoth2b000fd2016-04-06 06:37:15 -0700330 std::string getTimerName(TimerStackIdT StackID);
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700331 void setTimerName(TimerStackIdT StackID, const std::string &NewName);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700332
Andrew Scull57e12682015-09-16 11:30:19 -0700333 /// This is the first work item sequence number that the parser produces, and
334 /// correspondingly the first sequence number that the emitter thread will
335 /// wait for. Start numbering at 1 to leave room for a sentinel, in case e.g.
336 /// we wish to inject items with a special sequence number that may be
337 /// executed out of order.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700338 static constexpr uint32_t getFirstSequenceNumber() { return 1; }
Andrew Scull57e12682015-09-16 11:30:19 -0700339 /// Adds a newly parsed and constructed function to the Cfg work queue.
340 /// Notifies any idle workers that a new function is available for
341 /// translating. May block if the work queue is too large, in order to control
342 /// memory footprint.
Karl Schimpfe8457a22016-03-31 10:20:23 -0700343 void optQueueBlockingPush(std::unique_ptr<OptWorkItem> Item);
Andrew Scull57e12682015-09-16 11:30:19 -0700344 /// Takes a Cfg from the work queue for translating. May block if the work
345 /// queue is currently empty. Returns nullptr if there is no more work - the
346 /// queue is empty and either end() has been called or the Sequential flag was
347 /// set.
Karl Schimpfe8457a22016-03-31 10:20:23 -0700348 std::unique_ptr<OptWorkItem> optQueueBlockingPop();
Andrew Scull9612d322015-07-06 14:53:25 -0700349 /// Notifies that no more work will be added to the work queue.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800350 void optQueueNotifyEnd() { OptQ.notifyEnd(); }
351
Andrew Scull9612d322015-07-06 14:53:25 -0700352 /// Emit file header for output file.
Jan Voungfb792842015-06-11 15:27:50 -0700353 void emitFileHeader();
354
John Porto8b1a7052015-06-17 13:20:08 -0700355 void lowerConstants();
356
Andrew Scull86df4e92015-07-30 13:54:44 -0700357 void lowerJumpTables();
358
Jaydeep Patil3da9f652016-11-03 22:54:06 -0700359 /// Emit target specific read-only data sections if any. E.g., for MIPS this
360 /// generates a .MIPS.abiflags section.
361 void emitTargetRODataSections();
362
John Portobd2e2312016-03-15 11:06:25 -0700363 void emitQueueBlockingPush(std::unique_ptr<EmitterWorkItem> Item);
364 std::unique_ptr<EmitterWorkItem> emitQueueBlockingPop();
Jim Stichnothbbca7542015-02-11 16:08:31 -0800365 void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800366
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700367 void initParserThread();
368 void startWorkerThreads();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800369
Karl Schimpfe8457a22016-03-31 10:20:23 -0700370 void waitForWorkerThreads();
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800371
Thomas Livelyaab70992016-06-07 13:54:59 -0700372 /// sets the instrumentation object to use.
373 void setInstrumentation(std::unique_ptr<Instrumentation> Instr) {
374 if (!BuildDefs::minimal())
375 Instrumentor = std::move(Instr);
376 }
377
378 void instrumentFunc(Cfg *Func) {
379 if (!BuildDefs::minimal() && Instrumentor)
380 Instrumentor->instrumentFunc(Func);
381 }
382
Andrew Scull9612d322015-07-06 14:53:25 -0700383 /// Translation thread startup routine.
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700384 void translateFunctionsWrapper(ThreadContext *MyTLS);
Andrew Scull9612d322015-07-06 14:53:25 -0700385 /// Translate functions from the Cfg queue until the queue is empty.
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800386 void translateFunctions();
387
Andrew Scull9612d322015-07-06 14:53:25 -0700388 /// Emitter thread startup routine.
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700389 void emitterWrapper(ThreadContext *MyTLS);
Andrew Scull57e12682015-09-16 11:30:19 -0700390 /// Emit functions and global initializers from the emitter queue until the
391 /// queue is empty.
Jim Stichnothbbca7542015-02-11 16:08:31 -0800392 void emitItems();
393
Andrew Scull9612d322015-07-06 14:53:25 -0700394 /// Uses DataLowering to lower Globals. Side effects:
395 /// - discards the initializer list for the global variable in Globals.
396 /// - clears the Globals array.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700397 void lowerGlobals(const std::string &SectionSuffix);
John Porto8b1a7052015-06-17 13:20:08 -0700398
Andrew Scull9612d322015-07-06 14:53:25 -0700399 /// Lowers the profile information.
John Porto8b1a7052015-06-17 13:20:08 -0700400 void lowerProfileData();
401
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800402 void dumpConstantLookupCounts();
403
John Portoa78e4ba2016-03-15 09:28:04 -0700404 /// DisposeGlobalVariablesAfterLowering controls whether the memory used by
405 /// GlobaleVariables can be reclaimed right after they have been lowered.
406 /// @{
407 bool getDisposeGlobalVariablesAfterLowering() const {
408 return DisposeGlobalVariablesAfterLowering;
409 }
410
411 void setDisposeGlobalVariablesAfterLowering(bool Value) {
412 DisposeGlobalVariablesAfterLowering = Value;
413 }
414 /// @}
415
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700416 LockedPtr<StringPool> getStrings() const {
417 return LockedPtr<StringPool>(Strings.get(), &StringsLock);
418 }
419
Thomas Lively2c9992a2016-07-20 11:19:17 -0700420 LockedPtr<VariableDeclarationList> getGlobals() {
421 return LockedPtr<VariableDeclarationList>(&Globals, &InitAllocLock);
422 }
423
Karl Schimpf3018cf22016-04-11 14:49:01 -0700424 /// Number of function blocks that can be queued before waiting for
425 /// translation
426 /// threads to consume.
427 static constexpr size_t MaxOptQSize = 1 << 16;
428
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800429private:
430 // Try to ensure mutexes are allocated on separate cache lines.
431
John Porto1bec8bc2015-06-22 10:51:13 -0700432 // Destructors collaborate with Allocator
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800433 ICE_CACHELINE_BOUNDARY;
434 // Managed by getAllocator()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700435 mutable GlobalLockType AllocLock;
John Portoe82b5602016-02-24 15:58:55 -0800436 ArenaAllocator Allocator;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800437
438 ICE_CACHELINE_BOUNDARY;
John Portoa78e4ba2016-03-15 09:28:04 -0700439 // Managed by getInitializerAllocator()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700440 mutable GlobalLockType InitAllocLock;
John Portoa78e4ba2016-03-15 09:28:04 -0700441 VariableDeclarationList Globals;
442
443 ICE_CACHELINE_BOUNDARY;
John Porto1bec8bc2015-06-22 10:51:13 -0700444 // Managed by getDestructors()
Andrew Scull8072bae2015-09-14 16:01:26 -0700445 using DestructorArray = std::vector<std::function<void()>>;
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700446 mutable GlobalLockType DestructorsLock;
John Porto1bec8bc2015-06-22 10:51:13 -0700447 DestructorArray Destructors;
448
449 ICE_CACHELINE_BOUNDARY;
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700450 // Managed by getStrings()
451 mutable GlobalLockType StringsLock;
452 std::unique_ptr<StringPool> Strings;
453
454 ICE_CACHELINE_BOUNDARY;
455 // Managed by getConstPool()
456 mutable GlobalLockType ConstPoolLock;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800457 std::unique_ptr<ConstantPool> ConstPool;
458
459 ICE_CACHELINE_BOUNDARY;
Andrew Scull1eda90a2015-08-04 17:03:19 -0700460 // Managed by getJumpTableList()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700461 mutable GlobalLockType JumpTablesLock;
Andrew Scull1eda90a2015-08-04 17:03:19 -0700462 JumpTableDataList JumpTableList;
Andrew Scull86df4e92015-07-30 13:54:44 -0700463
464 ICE_CACHELINE_BOUNDARY;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800465 // Managed by getErrorStatus()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700466 mutable GlobalLockType ErrorStatusLock;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800467 ErrorCode ErrorStatus;
468
469 ICE_CACHELINE_BOUNDARY;
470 // Managed by getStatsCumulative()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700471 mutable GlobalLockType StatsLock;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800472 CodeStats StatsCumulative;
473
474 ICE_CACHELINE_BOUNDARY;
475 // Managed by getTimers()
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700476 mutable GlobalLockType TimerLock;
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800477 TimerList Timers;
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800478
479 ICE_CACHELINE_BOUNDARY;
Andrew Scull9612d322015-07-06 14:53:25 -0700480 /// StrLock is a global lock on the dump and emit output streams.
Andrew Scull8072bae2015-09-14 16:01:26 -0700481 using StrLockType = std::mutex;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800482 StrLockType StrLock;
Andrew Scull9612d322015-07-06 14:53:25 -0700483 Ostream *StrDump; /// Stream for dumping / diagnostics
484 Ostream *StrEmit; /// Stream for code emission
485 Ostream *StrError; /// Stream for logging errors.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700486
Karl Schimpfe8457a22016-03-31 10:20:23 -0700487 // True if waitForWorkerThreads() has been called.
488 std::atomic_bool WaitForWorkerThreadsCalled;
489
Jim Stichnothfa4efea2015-01-27 05:06:03 -0800490 ICE_CACHELINE_BOUNDARY;
491
Jan Voung3bd9f1a2014-06-18 10:50:57 -0700492 Intrinsics IntrinsicsInfo;
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;
Karl Schimpf3018cf22016-04-11 14:49:01 -0700495 // Value defining when to wake up the main parse thread.
496 const size_t OptQWakeupSize;
Karl Schimpfe8457a22016-03-31 10:20:23 -0700497 BoundedProducerConsumerQueue<OptWorkItem, MaxOptQSize> OptQ;
Jim Stichnothbbca7542015-02-11 16:08:31 -0800498 BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ;
John Porto8b1a7052015-06-17 13:20:08 -0700499 // DataLowering is only ever used by a single thread at a time (either in
500 // emitItems(), or in IceCompiler::run before the compilation is over.)
501 // TODO(jpp): move to EmitterContext.
502 std::unique_ptr<TargetDataLowering> DataLowering;
Andrew Scull9612d322015-07-06 14:53:25 -0700503 /// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true"
504 /// program global variables) until the first code WorkItem is seen.
John Porto8b1a7052015-06-17 13:20:08 -0700505 // TODO(jpp): move to EmitterContext.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700506 bool HasSeenCode = false;
Thomas Livelyaab70992016-06-07 13:54:59 -0700507 // If Instrumentor is not empty then it will be used to instrument globals and
508 // CFGs.
509 std::unique_ptr<Instrumentation> Instrumentor = nullptr;
John Porto8b1a7052015-06-17 13:20:08 -0700510 // TODO(jpp): move to EmitterContext.
John Portoa78e4ba2016-03-15 09:28:04 -0700511 VariableDeclaration *ProfileBlockInfoVarDecl = nullptr;
512 std::vector<VariableDeclaration *> ProfileBlockInfos;
513 /// Indicates if global variable declarations can be disposed of right after
514 /// lowering.
515 bool DisposeGlobalVariablesAfterLowering = true;
Karl Schimpf20070e82016-03-17 13:30:13 -0700516 Constant *ConstZeroForType[IceType_NUM];
517 Constant *ConstantTrue;
518 // Holds the constants representing each runtime helper function.
519 Constant *RuntimeHelperFunc[static_cast<size_t>(RuntimeHelper::H_Num)];
Jim Stichnoth217dc082014-07-11 14:06:55 -0700520
Karl Schimpf20070e82016-03-17 13:30:13 -0700521 Constant *getConstantZeroInternal(Type Ty);
522 Constant *getConstantIntInternal(Type Ty, int64_t Value);
523 Constant *getConstantInt1Internal(int8_t ConstantInt1);
524 Constant *getConstantInt8Internal(int8_t ConstantInt8);
525 Constant *getConstantInt16Internal(int16_t ConstantInt16);
526 Constant *getConstantInt32Internal(int32_t ConstantInt32);
527 Constant *getConstantInt64Internal(int64_t ConstantInt64);
John Portoe82b5602016-02-24 15:58:55 -0800528 LockedPtr<ArenaAllocator> getAllocator() {
529 return LockedPtr<ArenaAllocator>(&Allocator, &AllocLock);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800530 }
John Portoa78e4ba2016-03-15 09:28:04 -0700531 LockedPtr<VariableDeclarationList> getInitializerAllocator() {
532 return LockedPtr<VariableDeclarationList>(&Globals, &InitAllocLock);
533 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800534 LockedPtr<ConstantPool> getConstPool() {
535 return LockedPtr<ConstantPool>(ConstPool.get(), &ConstPoolLock);
536 }
Andrew Scull1eda90a2015-08-04 17:03:19 -0700537 LockedPtr<JumpTableDataList> getJumpTableList() {
538 return LockedPtr<JumpTableDataList>(&JumpTableList, &JumpTablesLock);
539 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800540 LockedPtr<CodeStats> getStatsCumulative() {
541 return LockedPtr<CodeStats>(&StatsCumulative, &StatsLock);
542 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800543 LockedPtr<TimerList> getTimers() {
544 return LockedPtr<TimerList>(&Timers, &TimerLock);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800545 }
John Porto1bec8bc2015-06-22 10:51:13 -0700546 LockedPtr<DestructorArray> getDestructors() {
547 return LockedPtr<DestructorArray>(&Destructors, &DestructorsLock);
548 }
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800549
John Porto8b1a7052015-06-17 13:20:08 -0700550 void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
John Portoa78e4ba2016-03-15 09:28:04 -0700551 LockedPtr<VariableDeclarationList> _(&Globals, &InitAllocLock);
552 if (Globls != nullptr) {
553 Globals.merge(Globls.get());
Thomas Lively2c9992a2016-07-20 11:19:17 -0700554 if (!BuildDefs::minimal() && Instrumentor != nullptr)
555 Instrumentor->setHasSeenGlobals();
John Portoa78e4ba2016-03-15 09:28:04 -0700556 }
John Porto8b1a7052015-06-17 13:20:08 -0700557 }
558
559 void lowerGlobalsIfNoCodeHasBeenSeen() {
560 if (HasSeenCode)
561 return;
562 constexpr char NoSuffix[] = "";
563 lowerGlobals(NoSuffix);
564 HasSeenCode = true;
565 }
566
John Portoa78e4ba2016-03-15 09:28:04 -0700567 void saveBlockInfoPtrs();
John Porto844211e2016-02-04 08:42:48 -0800568
Jim Stichnothbbca7542015-02-11 16:08:31 -0800569 llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
570 llvm::SmallVector<std::thread, 128> TranslationThreads;
571 llvm::SmallVector<std::thread, 128> EmitterThreads;
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800572 // Each thread has its own TLS pointer which is also held in
573 // AllThreadContexts.
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800574 ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS);
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800575
Jim Stichnotha5fe17a2015-01-26 11:10:03 -0800576public:
Lei Zhang04e9b1c2017-05-23 15:08:59 -0700577 static void TlsInit();
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700578};
579
Andrew Scull57e12682015-09-16 11:30:19 -0700580/// Helper class to push and pop a timer marker. The constructor pushes a
581/// marker, and the destructor pops it. This is for convenient timing of regions
582/// of code.
Jim Stichnothc4554d72014-09-30 16:49:38 -0700583class TimerMarker {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800584 TimerMarker() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700585 TimerMarker(const TimerMarker &) = delete;
586 TimerMarker &operator=(const TimerMarker &) = delete;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700587
588public:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800589 TimerMarker(TimerIdT ID, GlobalContext *Ctx,
590 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700591 : ID(ID), Ctx(Ctx), StackID(StackID) {
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800592 if (BuildDefs::timers())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800593 push();
Jim Stichnothc4554d72014-09-30 16:49:38 -0700594 }
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800595 TimerMarker(TimerIdT ID, const Cfg *Func,
596 TimerStackIdT StackID = GlobalContext::TSK_Default)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700597 : ID(ID), Ctx(nullptr), StackID(StackID) {
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800598 // Ctx gets set at the beginning of pushCfg().
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800599 if (BuildDefs::timers())
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800600 pushCfg(Func);
601 }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700602 TimerMarker(GlobalContext *Ctx, const std::string &FuncName)
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800603 : ID(getTimerIdFromFuncName(Ctx, FuncName)), Ctx(Ctx),
604 StackID(GlobalContext::TSK_Funcs) {
605 if (BuildDefs::timers())
606 push();
607 }
Jim Stichnoth8363a062014-10-07 10:02:38 -0700608
Jim Stichnothc4554d72014-09-30 16:49:38 -0700609 ~TimerMarker() {
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800610 if (BuildDefs::timers() && Active)
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800611 Ctx->popTimer(ID, StackID);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700612 }
613
614private:
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800615 void push();
616 void pushCfg(const Cfg *Func);
Jim Stichnothb88d8c82016-03-11 15:33:00 -0800617 static TimerIdT getTimerIdFromFuncName(GlobalContext *Ctx,
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700618 const std::string &FuncName);
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800619 const TimerIdT ID;
620 GlobalContext *Ctx;
621 const TimerStackIdT StackID;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700622 bool Active = false;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700623};
624
Andrew Scull57e12682015-09-16 11:30:19 -0700625/// Helper class for locking the streams and then automatically unlocking them.
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800626class OstreamLocker {
627private:
628 OstreamLocker() = delete;
629 OstreamLocker(const OstreamLocker &) = delete;
630 OstreamLocker &operator=(const OstreamLocker &) = delete;
631
632public:
633 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); }
634 ~OstreamLocker() { Ctx->unlockStr(); }
635
636private:
637 GlobalContext *const Ctx;
638};
639
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700640} // end of namespace Ice
641
642#endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H