Commit a5fe17a1 by Jim Stichnoth

Subzero: Second attempt at fixing MacOS 10.6 build.

Manages thread_local pointer fields through a set of macros. If ICE_THREAD_LOCAL_HACK is defined, the thread_local definitions and accesses are defined in terms of pthread operations. This assumes that the underlying std::thread library is based on pthread. BUG= none R=jfb@chromium.org, jvoung@chromium.org Review URL: https://codereview.chromium.org/872933002
parent fed97aff
......@@ -25,7 +25,7 @@
namespace Ice {
ICE_ATTRIBUTE_TLS const Cfg *Cfg::CurrentCfg = nullptr;
ICE_TLS_DEFINE_FIELD(const Cfg *, Cfg, CurrentCfg);
ArenaAllocator<> *getCurrentCfgAllocator() {
return Cfg::getCurrentCfgAllocator();
......
......@@ -37,15 +37,15 @@ public:
// destruction requirements more explicit.
static Cfg *create(GlobalContext *Ctx) {
Cfg *Func = new Cfg(Ctx);
CurrentCfg = Func;
ICE_TLS_SET_FIELD(CurrentCfg, Func);
return Func;
}
// Gets a pointer to the current thread's Cfg.
static const Cfg *getCurrentCfg() { return CurrentCfg; }
static const Cfg *getCurrentCfg() { return ICE_TLS_GET_FIELD(CurrentCfg); }
// Gets a pointer to the current thread's Cfg's allocator.
static ArenaAllocator<> *getCurrentCfgAllocator() {
assert(CurrentCfg);
return CurrentCfg->Allocator.get();
assert(ICE_TLS_GET_FIELD(CurrentCfg));
return ICE_TLS_GET_FIELD(CurrentCfg)->Allocator.get();
}
GlobalContext *getContext() const { return Ctx; }
......@@ -213,7 +213,10 @@ private:
// Maintain a pointer in TLS to the current Cfg being translated.
// This is primarily for accessing its allocator statelessly, but
// other uses are possible.
ICE_ATTRIBUTE_TLS static const Cfg *CurrentCfg;
ICE_TLS_DECLARE_FIELD(const Cfg *, CurrentCfg);
public:
static void TlsInit() { ICE_TLS_INIT_FIELD(CurrentCfg); }
};
} // end of namespace Ice
......
......@@ -38,14 +38,7 @@
#include "llvm/Support/ELF.h"
#include "llvm/Support/raw_ostream.h"
// TODO(stichnot): Define ICE_ATTRIBUTE_TLS as thread_local after all
// compilers support that C++11 keyword. In particular, MacOS 10.6
// does not support it.
#if defined (_MSC_VER)
#define ICE_ATTRIBUTE_TLS __declspec(thread)
#else // !_MSC_VER
#define ICE_ATTRIBUTE_TLS __thread
#endif // !_MSC_VER
#include "IceTLS.h"
namespace Ice {
......
......@@ -132,11 +132,18 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit,
: StrDump(OsDump), StrEmit(OsEmit), VMask(Mask),
ConstPool(new ConstantPool()), Arch(Arch), Opt(Opt),
TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter() {
// Make sure thread_local fields are properly initialized before any
// accesses are made. Do this here instead of at the start of
// main() so that all clients (e.g. unit tests) can benefit for
// free.
GlobalContext::TlsInit();
Cfg::TlsInit();
// Create a new ThreadContext for the current thread. No need to
// lock AllThreadContexts at this point since no other threads have
// access yet to this GlobalContext object.
AllThreadContexts.push_back(new ThreadContext());
TLS = AllThreadContexts.back();
ICE_TLS_SET_FIELD(TLS, AllThreadContexts.back());
// Pre-register built-in stack names.
if (ALLOW_DUMP) {
// TODO(stichnot): There needs to be a strong relationship between
......@@ -495,7 +502,7 @@ void GlobalContext::dumpStats(const IceString &Name, bool Final) {
if (Final) {
getStatsCumulative()->dump(Name, getStrDump());
} else {
TLS->StatsFunction.dump(Name, getStrDump());
ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump());
getStatsCumulative()->dump("_TOTAL_", getStrDump());
}
}
......@@ -518,6 +525,6 @@ TimerMarker::TimerMarker(TimerIdT ID, const Cfg *Func)
}
}
ICE_ATTRIBUTE_TLS GlobalContext::ThreadContext *GlobalContext::TLS;
ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS);
} // end of namespace Ice
......@@ -179,37 +179,37 @@ public:
// Reset stats at the beginning of a function.
void resetStats() {
if (ALLOW_DUMP)
TLS->StatsFunction.reset();
ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset();
}
void dumpStats(const IceString &Name, bool Final = false);
void statsUpdateEmitted(uint32_t InstCount) {
if (!ALLOW_DUMP || !getFlags().DumpStats)
return;
TLS->StatsFunction.updateEmitted(InstCount);
ICE_TLS_GET_FIELD(TLS)->StatsFunction.updateEmitted(InstCount);
getStatsCumulative()->updateEmitted(InstCount);
}
void statsUpdateRegistersSaved(uint32_t Num) {
if (!ALLOW_DUMP || !getFlags().DumpStats)
return;
TLS->StatsFunction.updateRegistersSaved(Num);
ICE_TLS_GET_FIELD(TLS)->StatsFunction.updateRegistersSaved(Num);
getStatsCumulative()->updateRegistersSaved(Num);
}
void statsUpdateFrameBytes(uint32_t Bytes) {
if (!ALLOW_DUMP || !getFlags().DumpStats)
return;
TLS->StatsFunction.updateFrameBytes(Bytes);
ICE_TLS_GET_FIELD(TLS)->StatsFunction.updateFrameBytes(Bytes);
getStatsCumulative()->updateFrameBytes(Bytes);
}
void statsUpdateSpills() {
if (!ALLOW_DUMP || !getFlags().DumpStats)
return;
TLS->StatsFunction.updateSpills();
ICE_TLS_GET_FIELD(TLS)->StatsFunction.updateSpills();
getStatsCumulative()->updateSpills();
}
void statsUpdateFills() {
if (!ALLOW_DUMP || !getFlags().DumpStats)
return;
TLS->StatsFunction.updateFills();
ICE_TLS_GET_FIELD(TLS)->StatsFunction.updateFills();
getStatsCumulative()->updateFills();
}
......@@ -274,11 +274,14 @@ private:
std::vector<ThreadContext *> AllThreadContexts;
// Each thread has its own TLS pointer which is also held in
// AllThreadContexts.
ICE_ATTRIBUTE_TLS static ThreadContext *TLS;
ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS);
// Private helpers for mangleName()
typedef llvm::SmallVector<char, 32> ManglerVector;
void incrementSubstitutions(ManglerVector &OldName) const;
public:
static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); }
};
// Helper class to push and pop a timer marker. The constructor
......
//===- subzero/src/IceTLS.h - thread_local workaround -----------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines macros for working around the lack of support for
// thread_local in MacOS 10.6. It assumes std::thread is written in
// terms of pthread. Define ICE_THREAD_LOCAL_HACK to enable the
// pthread workarounds.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETLS_H
#define SUBZERO_SRC_ICETLS_H
#if defined(_MSC_VER)
#define ICE_ATTRIBUTE_TLS __declspec(thread)
#else // !_MSC_VER
#define ICE_ATTRIBUTE_TLS thread_local
#endif // !_MSC_VER
// Defines 4 macros for unifying thread_local and pthread:
//
// ICE_TLS_DECLARE_FIELD(Type, FieldName): Declare a static
// thread_local field inside the current class definition. "Type"
// needs to be a pointer type, such as int* or class Foo*.
//
// ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName): Define a static
// thread_local field outside of its class definition. The field will
// ultimately be initialized to nullptr.
//
// ICE_TLS_INIT_FIELD(FieldName): Ensure the thread_local field is
// properly initialized. This is intended to be called from within a
// static method of the field's class after main() starts (to ensure
// that the pthread library is fully initialized) but before any uses
// of ICE_TLS_GET_FIELD or ICE_TLS_SET_FIELD.
//
// ICE_TLS_GET_FIELD(Type, FieldName): Read the value of the static
// thread_local field. Must be done within the context of its class.
//
// ICE_TLS_SET_FIELD(FieldName, Value): Write a value into the static
// thread_local field. Must be done within the context of its class.
// TODO(stichnot): Limit this define to only the platforms that
// absolutely require it. And ideally, eventually remove this hack
// altogether.
#define ICE_THREAD_LOCAL_HACK
#ifdef ICE_THREAD_LOCAL_HACK
// For a static thread_local field F of a class C, instead of
// declaring and defining C::F, we create two static fields:
// static pthread_key_t F__key;
// static int F__initStatus;
//
// The F__initStatus field is used to hold the result of the
// pthread_key_create() call, where a zero value indicates success,
// and a nonzero value indicates failure or that ICE_TLS_INIT_FIELD()
// was never called.
// The F__key field is used as the argument to
// pthread_getspecific() and pthread_setspecific().
#include <pthread.h>
#define ICE_TLS_DECLARE_FIELD(Type, FieldName) \
typedef Type FieldName##__type; \
static pthread_key_t FieldName##__key; \
static int FieldName##__initStatus
#define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName) \
pthread_key_t ClassName::FieldName##__key; \
int ClassName::FieldName##__initStatus = 1;
#define ICE_TLS_INIT_FIELD(FieldName) \
if (FieldName##__initStatus) { \
FieldName##__initStatus = pthread_key_create(&FieldName##__key, nullptr); \
if (FieldName##__initStatus) \
llvm::report_fatal_error("Failed to create pthread key"); \
}
#define ICE_TLS_GET_FIELD(FieldName) \
(assert(FieldName##__initStatus == 0), \
static_cast<FieldName##__type>(pthread_getspecific(FieldName##__key)))
#define ICE_TLS_SET_FIELD(FieldName, Value) \
(assert(FieldName##__initStatus == 0), \
pthread_setspecific(FieldName##__key, (Value)))
#else // !ICE_THREAD_LOCAL_HACK
#define ICE_TLS_DECLARE_FIELD(Type, FieldName) \
static ICE_ATTRIBUTE_TLS Type FieldName
#define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName) \
ICE_ATTRIBUTE_TLS Type ClassName::FieldName = nullptr
#define ICE_TLS_INIT_FIELD(FieldName)
#define ICE_TLS_GET_FIELD(FieldName) (FieldName)
#define ICE_TLS_SET_FIELD(FieldName, Value) (FieldName = (Value))
#endif // !ICE_THREAD_LOCAL_HACK
#endif // SUBZERO_SRC_ICETLS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment