| OLD | NEW |
| 1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===// | 1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// This file declares aspects of the compilation that persist across | 11 /// This file declares aspects of the compilation that persist across multiple |
| 12 /// multiple functions. | 12 /// functions. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H | 16 #ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H |
| 17 #define SUBZERO_SRC_ICEGLOBALCONTEXT_H | 17 #define SUBZERO_SRC_ICEGLOBALCONTEXT_H |
| 18 | 18 |
| 19 #include "IceDefs.h" | 19 #include "IceDefs.h" |
| 20 #include "IceClFlags.h" | 20 #include "IceClFlags.h" |
| 21 #include "IceIntrinsics.h" | 21 #include "IceIntrinsics.h" |
| 22 #include "IceRNG.h" | 22 #include "IceRNG.h" |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 LockedPtr<ErrorCode> getErrorStatus() { | 179 LockedPtr<ErrorCode> getErrorStatus() { |
| 180 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock); | 180 return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock); |
| 181 } | 181 } |
| 182 | 182 |
| 183 /// When emitting assembly, we allow a string to be prepended to | 183 /// When emitting assembly, we allow a string to be prepended to |
| 184 /// names of translated functions. This makes it easier to create an | 184 /// names of translated functions. This makes it easier to create an |
| 185 /// execution test against a reference translator like llc, with both | 185 /// execution test against a reference translator like llc, with both |
| 186 /// translators using the same bitcode as input. | 186 /// translators using the same bitcode as input. |
| 187 IceString mangleName(const IceString &Name) const; | 187 IceString mangleName(const IceString &Name) const; |
| 188 | 188 |
| 189 // Manage Constants. | 189 /// \name Manage Constants. |
| 190 // getConstant*() functions are not const because they might add | 190 /// @{ |
| 191 // something to the constant pool. | 191 // getConstant*() functions are not const because they might add something to |
| 192 // the constant pool. |
| 192 Constant *getConstantInt(Type Ty, int64_t Value); | 193 Constant *getConstantInt(Type Ty, int64_t Value); |
| 193 Constant *getConstantInt1(int8_t ConstantInt1); | 194 Constant *getConstantInt1(int8_t ConstantInt1); |
| 194 Constant *getConstantInt8(int8_t ConstantInt8); | 195 Constant *getConstantInt8(int8_t ConstantInt8); |
| 195 Constant *getConstantInt16(int16_t ConstantInt16); | 196 Constant *getConstantInt16(int16_t ConstantInt16); |
| 196 Constant *getConstantInt32(int32_t ConstantInt32); | 197 Constant *getConstantInt32(int32_t ConstantInt32); |
| 197 Constant *getConstantInt64(int64_t ConstantInt64); | 198 Constant *getConstantInt64(int64_t ConstantInt64); |
| 198 Constant *getConstantFloat(float Value); | 199 Constant *getConstantFloat(float Value); |
| 199 Constant *getConstantDouble(double Value); | 200 Constant *getConstantDouble(double Value); |
| 200 /// Returns a symbolic constant. | 201 /// Returns a symbolic constant. |
| 201 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name, | 202 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name, |
| 202 bool SuppressMangling); | 203 bool SuppressMangling); |
| 203 Constant *getConstantExternSym(const IceString &Name); | 204 Constant *getConstantExternSym(const IceString &Name); |
| 204 /// Returns an undef. | 205 /// Returns an undef. |
| 205 Constant *getConstantUndef(Type Ty); | 206 Constant *getConstantUndef(Type Ty); |
| 206 /// Returns a zero value. | 207 /// Returns a zero value. |
| 207 Constant *getConstantZero(Type Ty); | 208 Constant *getConstantZero(Type Ty); |
| 208 /// getConstantPool() returns a copy of the constant pool for | 209 /// getConstantPool() returns a copy of the constant pool for constants of a |
| 209 /// constants of a given type. | 210 /// given type. |
| 210 ConstantList getConstantPool(Type Ty); | 211 ConstantList getConstantPool(Type Ty); |
| 211 /// Returns a copy of the list of external symbols. | 212 /// Returns a copy of the list of external symbols. |
| 212 ConstantList getConstantExternSyms(); | 213 ConstantList getConstantExternSyms(); |
| 214 /// @} |
| 213 | 215 |
| 214 /// Return a locked pointer to the registered jump tables. | 216 /// Return a locked pointer to the registered jump tables. |
| 215 JumpTableDataList getJumpTables(); | 217 JumpTableDataList getJumpTables(); |
| 216 /// Create a new jump table entry and return a reference to it. | 218 /// Create a new jump table entry and return a reference to it. |
| 217 JumpTableData &addJumpTable(IceString FuncName, SizeT Id, SizeT NumTargets); | 219 JumpTableData &addJumpTable(IceString FuncName, SizeT Id, SizeT NumTargets); |
| 218 | 220 |
| 219 const ClFlags &getFlags() const { return Flags; } | 221 const ClFlags &getFlags() const { return Flags; } |
| 220 | 222 |
| 221 bool isIRGenerationDisabled() const { | 223 bool isIRGenerationDisabled() const { |
| 222 return getFlags().getDisableIRGeneration(); | 224 return getFlags().getDisableIRGeneration(); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 if (!getFlags().getDumpStats()) | 294 if (!getFlags().getDumpStats()) |
| 293 return; | 295 return; |
| 294 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); | 296 ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS); |
| 295 Tls->StatsFunction.update(CodeStats::CS_NumRPImms); | 297 Tls->StatsFunction.update(CodeStats::CS_NumRPImms); |
| 296 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms); | 298 Tls->StatsCumulative.update(CodeStats::CS_NumRPImms); |
| 297 } | 299 } |
| 298 | 300 |
| 299 /// These are predefined TimerStackIdT values. | 301 /// These are predefined TimerStackIdT values. |
| 300 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num }; | 302 enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num }; |
| 301 | 303 |
| 302 /// newTimerStackID() creates a new TimerStack in the global space. | 304 /// newTimerStackID() creates a new TimerStack in the global space. It does |
| 303 /// It does not affect any TimerStack objects in TLS. | 305 /// not affect any TimerStack objects in TLS. |
| 304 TimerStackIdT newTimerStackID(const IceString &Name); | 306 TimerStackIdT newTimerStackID(const IceString &Name); |
| 305 /// dumpTimers() dumps the global timer data. As such, one probably | 307 /// dumpTimers() dumps the global timer data. As such, one probably wants to |
| 306 /// wants to call mergeTimerStacks() as a prerequisite. | 308 /// call mergeTimerStacks() as a prerequisite. |
| 307 void dumpTimers(TimerStackIdT StackID = TSK_Default, | 309 void dumpTimers(TimerStackIdT StackID = TSK_Default, |
| 308 bool DumpCumulative = true); | 310 bool DumpCumulative = true); |
| 309 /// The following methods affect only the calling thread's TLS timer | 311 /// The following methods affect only the calling thread's TLS timer data. |
| 310 /// data. | |
| 311 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name); | 312 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name); |
| 312 void pushTimer(TimerIdT ID, TimerStackIdT StackID); | 313 void pushTimer(TimerIdT ID, TimerStackIdT StackID); |
| 313 void popTimer(TimerIdT ID, TimerStackIdT StackID); | 314 void popTimer(TimerIdT ID, TimerStackIdT StackID); |
| 314 void resetTimer(TimerStackIdT StackID); | 315 void resetTimer(TimerStackIdT StackID); |
| 315 void setTimerName(TimerStackIdT StackID, const IceString &NewName); | 316 void setTimerName(TimerStackIdT StackID, const IceString &NewName); |
| 316 | 317 |
| 317 /// This is the first work item sequence number that the parser | 318 /// This is the first work item sequence number that the parser produces, and |
| 318 /// produces, and correspondingly the first sequence number that the | 319 /// correspondingly the first sequence number that the emitter thread will |
| 319 /// emitter thread will wait for. Start numbering at 1 to leave room | 320 /// wait for. Start numbering at 1 to leave room for a sentinel, in case e.g. |
| 320 /// for a sentinel, in case e.g. we wish to inject items with a | 321 /// we wish to inject items with a special sequence number that may be |
| 321 /// special sequence number that may be executed out of order. | 322 /// executed out of order. |
| 322 static uint32_t getFirstSequenceNumber() { return 1; } | 323 static uint32_t getFirstSequenceNumber() { return 1; } |
| 323 /// Adds a newly parsed and constructed function to the Cfg work | 324 /// Adds a newly parsed and constructed function to the Cfg work queue. |
| 324 /// queue. Notifies any idle workers that a new function is | 325 /// Notifies any idle workers that a new function is available for |
| 325 /// available for translating. May block if the work queue is too | 326 /// translating. May block if the work queue is too large, in order to control |
| 326 /// large, in order to control memory footprint. | 327 /// memory footprint. |
| 327 void optQueueBlockingPush(std::unique_ptr<Cfg> Func); | 328 void optQueueBlockingPush(std::unique_ptr<Cfg> Func); |
| 328 /// Takes a Cfg from the work queue for translating. May block if | 329 /// Takes a Cfg from the work queue for translating. May block if the work |
| 329 /// the work queue is currently empty. Returns nullptr if there is | 330 /// queue is currently empty. Returns nullptr if there is no more work - the |
| 330 /// no more work - the queue is empty and either end() has been | 331 /// queue is empty and either end() has been called or the Sequential flag was |
| 331 /// called or the Sequential flag was set. | 332 /// set. |
| 332 std::unique_ptr<Cfg> optQueueBlockingPop(); | 333 std::unique_ptr<Cfg> optQueueBlockingPop(); |
| 333 /// Notifies that no more work will be added to the work queue. | 334 /// Notifies that no more work will be added to the work queue. |
| 334 void optQueueNotifyEnd() { OptQ.notifyEnd(); } | 335 void optQueueNotifyEnd() { OptQ.notifyEnd(); } |
| 335 | 336 |
| 336 /// Emit file header for output file. | 337 /// Emit file header for output file. |
| 337 void emitFileHeader(); | 338 void emitFileHeader(); |
| 338 | 339 |
| 339 void lowerConstants(); | 340 void lowerConstants(); |
| 340 | 341 |
| 341 void lowerJumpTables(); | 342 void lowerJumpTables(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 371 } | 372 } |
| 372 } | 373 } |
| 373 | 374 |
| 374 void waitForWorkerThreads() { | 375 void waitForWorkerThreads() { |
| 375 optQueueNotifyEnd(); | 376 optQueueNotifyEnd(); |
| 376 for (std::thread &Worker : TranslationThreads) { | 377 for (std::thread &Worker : TranslationThreads) { |
| 377 Worker.join(); | 378 Worker.join(); |
| 378 } | 379 } |
| 379 TranslationThreads.clear(); | 380 TranslationThreads.clear(); |
| 380 | 381 |
| 381 // Only notify the emit queue to end after all the translation | 382 // Only notify the emit queue to end after all the translation threads have |
| 382 // threads have ended. | 383 // ended. |
| 383 emitQueueNotifyEnd(); | 384 emitQueueNotifyEnd(); |
| 384 for (std::thread &Worker : EmitterThreads) { | 385 for (std::thread &Worker : EmitterThreads) { |
| 385 Worker.join(); | 386 Worker.join(); |
| 386 } | 387 } |
| 387 EmitterThreads.clear(); | 388 EmitterThreads.clear(); |
| 388 | 389 |
| 389 if (BuildDefs::dump()) { | 390 if (BuildDefs::dump()) { |
| 390 auto Timers = getTimers(); | 391 auto Timers = getTimers(); |
| 391 for (ThreadContext *TLS : AllThreadContexts) | 392 for (ThreadContext *TLS : AllThreadContexts) |
| 392 Timers->mergeFrom(TLS->Timers); | 393 Timers->mergeFrom(TLS->Timers); |
| 393 } | 394 } |
| 394 if (BuildDefs::dump()) { | 395 if (BuildDefs::dump()) { |
| 395 // Do a separate loop over AllThreadContexts to avoid holding | 396 // Do a separate loop over AllThreadContexts to avoid holding two locks |
| 396 // two locks at once. | 397 // at once. |
| 397 auto Stats = getStatsCumulative(); | 398 auto Stats = getStatsCumulative(); |
| 398 for (ThreadContext *TLS : AllThreadContexts) | 399 for (ThreadContext *TLS : AllThreadContexts) |
| 399 Stats->add(TLS->StatsCumulative); | 400 Stats->add(TLS->StatsCumulative); |
| 400 } | 401 } |
| 401 } | 402 } |
| 402 | 403 |
| 403 /// Translation thread startup routine. | 404 /// Translation thread startup routine. |
| 404 void translateFunctionsWrapper(ThreadContext *MyTLS) { | 405 void translateFunctionsWrapper(ThreadContext *MyTLS) { |
| 405 ICE_TLS_SET_FIELD(TLS, MyTLS); | 406 ICE_TLS_SET_FIELD(TLS, MyTLS); |
| 406 translateFunctions(); | 407 translateFunctions(); |
| 407 } | 408 } |
| 408 /// Translate functions from the Cfg queue until the queue is empty. | 409 /// Translate functions from the Cfg queue until the queue is empty. |
| 409 void translateFunctions(); | 410 void translateFunctions(); |
| 410 | 411 |
| 411 /// Emitter thread startup routine. | 412 /// Emitter thread startup routine. |
| 412 void emitterWrapper(ThreadContext *MyTLS) { | 413 void emitterWrapper(ThreadContext *MyTLS) { |
| 413 ICE_TLS_SET_FIELD(TLS, MyTLS); | 414 ICE_TLS_SET_FIELD(TLS, MyTLS); |
| 414 emitItems(); | 415 emitItems(); |
| 415 } | 416 } |
| 416 /// Emit functions and global initializers from the emitter queue | 417 /// Emit functions and global initializers from the emitter queue until the |
| 417 /// until the queue is empty. | 418 /// queue is empty. |
| 418 void emitItems(); | 419 void emitItems(); |
| 419 | 420 |
| 420 /// Uses DataLowering to lower Globals. Side effects: | 421 /// Uses DataLowering to lower Globals. Side effects: |
| 421 /// - discards the initializer list for the global variable in Globals. | 422 /// - discards the initializer list for the global variable in Globals. |
| 422 /// - clears the Globals array. | 423 /// - clears the Globals array. |
| 423 void lowerGlobals(const IceString &SectionSuffix); | 424 void lowerGlobals(const IceString &SectionSuffix); |
| 424 | 425 |
| 425 /// Lowers the profile information. | 426 /// Lowers the profile information. |
| 426 void lowerProfileData(); | 427 void lowerProfileData(); |
| 427 | 428 |
| 428 /// Utility function to match a symbol name against a match string. | 429 /// Utility function to match a symbol name against a match string. This is |
| 429 /// This is used in a few cases where we want to take some action on | 430 /// used in a few cases where we want to take some action on a particular |
| 430 /// a particular function or symbol based on a command-line argument, | 431 /// function or symbol based on a command-line argument, such as changing the |
| 431 /// such as changing the verbose level for a particular function. An | 432 /// verbose level for a particular function. An empty Match argument means |
| 432 /// empty Match argument means match everything. Returns true if | 433 /// match everything. Returns true if there is a match. |
| 433 /// there is a match. | |
| 434 static bool matchSymbolName(const IceString &SymbolName, | 434 static bool matchSymbolName(const IceString &SymbolName, |
| 435 const IceString &Match) { | 435 const IceString &Match) { |
| 436 return Match.empty() || Match == SymbolName; | 436 return Match.empty() || Match == SymbolName; |
| 437 } | 437 } |
| 438 | 438 |
| 439 private: | 439 private: |
| 440 // Try to ensure mutexes are allocated on separate cache lines. | 440 // Try to ensure mutexes are allocated on separate cache lines. |
| 441 | 441 |
| 442 // Destructors collaborate with Allocator | 442 // Destructors collaborate with Allocator |
| 443 ICE_CACHELINE_BOUNDARY; | 443 ICE_CACHELINE_BOUNDARY; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS); | 545 ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS); |
| 546 | 546 |
| 547 // Private helpers for mangleName() | 547 // Private helpers for mangleName() |
| 548 using ManglerVector = llvm::SmallVector<char, 32>; | 548 using ManglerVector = llvm::SmallVector<char, 32>; |
| 549 void incrementSubstitutions(ManglerVector &OldName) const; | 549 void incrementSubstitutions(ManglerVector &OldName) const; |
| 550 | 550 |
| 551 public: | 551 public: |
| 552 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); } | 552 static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); } |
| 553 }; | 553 }; |
| 554 | 554 |
| 555 /// Helper class to push and pop a timer marker. The constructor | 555 /// Helper class to push and pop a timer marker. The constructor pushes a |
| 556 /// pushes a marker, and the destructor pops it. This is for | 556 /// marker, and the destructor pops it. This is for convenient timing of regions |
| 557 /// convenient timing of regions of code. | 557 /// of code. |
| 558 class TimerMarker { | 558 class TimerMarker { |
| 559 TimerMarker() = delete; | 559 TimerMarker() = delete; |
| 560 TimerMarker(const TimerMarker &) = delete; | 560 TimerMarker(const TimerMarker &) = delete; |
| 561 TimerMarker &operator=(const TimerMarker &) = delete; | 561 TimerMarker &operator=(const TimerMarker &) = delete; |
| 562 | 562 |
| 563 public: | 563 public: |
| 564 TimerMarker(TimerIdT ID, GlobalContext *Ctx, | 564 TimerMarker(TimerIdT ID, GlobalContext *Ctx, |
| 565 TimerStackIdT StackID = GlobalContext::TSK_Default) | 565 TimerStackIdT StackID = GlobalContext::TSK_Default) |
| 566 : ID(ID), Ctx(Ctx), StackID(StackID) { | 566 : ID(ID), Ctx(Ctx), StackID(StackID) { |
| 567 if (BuildDefs::dump()) | 567 if (BuildDefs::dump()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 582 | 582 |
| 583 private: | 583 private: |
| 584 void push(); | 584 void push(); |
| 585 void pushCfg(const Cfg *Func); | 585 void pushCfg(const Cfg *Func); |
| 586 const TimerIdT ID; | 586 const TimerIdT ID; |
| 587 GlobalContext *Ctx; | 587 GlobalContext *Ctx; |
| 588 const TimerStackIdT StackID; | 588 const TimerStackIdT StackID; |
| 589 bool Active = false; | 589 bool Active = false; |
| 590 }; | 590 }; |
| 591 | 591 |
| 592 /// Helper class for locking the streams and then automatically | 592 /// Helper class for locking the streams and then automatically unlocking them. |
| 593 /// unlocking them. | |
| 594 class OstreamLocker { | 593 class OstreamLocker { |
| 595 private: | 594 private: |
| 596 OstreamLocker() = delete; | 595 OstreamLocker() = delete; |
| 597 OstreamLocker(const OstreamLocker &) = delete; | 596 OstreamLocker(const OstreamLocker &) = delete; |
| 598 OstreamLocker &operator=(const OstreamLocker &) = delete; | 597 OstreamLocker &operator=(const OstreamLocker &) = delete; |
| 599 | 598 |
| 600 public: | 599 public: |
| 601 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } | 600 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); } |
| 602 ~OstreamLocker() { Ctx->unlockStr(); } | 601 ~OstreamLocker() { Ctx->unlockStr(); } |
| 603 | 602 |
| 604 private: | 603 private: |
| 605 GlobalContext *const Ctx; | 604 GlobalContext *const Ctx; |
| 606 }; | 605 }; |
| 607 | 606 |
| 608 } // end of namespace Ice | 607 } // end of namespace Ice |
| 609 | 608 |
| 610 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H | 609 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H |
| OLD | NEW |