summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid M Peixotto <dmp@rice.edu>2011-06-28 15:31:42 -0500
committerDavid M Peixotto <dmp@rice.edu>2011-10-07 16:48:34 -0500
commitdba7254566b121408e7167200d0223a531b66e8b (patch)
tree0a3bfcb739b35123822cb644db93081b46c54fca
parent29a97fded4010bd01aa0a17945c84258e285d421 (diff)
downloadhaskell-dba7254566b121408e7167200d0223a531b66e8b.tar.gz
Enable pthread_getspecific() tls for LLVM compiler
LLVM does not support the __thread attribute for thread local storage and may generate incorrect code for global register variables. We want to allow building the runtime with LLVM-based compilers such as llvm-gcc and clang, particularly for MacOS. This patch changes the gct variable used by the garbage collector to use pthread_getspecific() for thread local storage when an llvm based compiler is used to build the runtime.
-rw-r--r--includes/Stg.h5
-rw-r--r--rts/StgCRun.c14
-rw-r--r--rts/Task.c13
-rw-r--r--rts/Task.h11
-rw-r--r--rts/sm/GC.c2
-rw-r--r--rts/sm/GCTDecl.h15
6 files changed, 51 insertions, 9 deletions
diff --git a/includes/Stg.h b/includes/Stg.h
index 5665018d93..5b3b20d4d6 100644
--- a/includes/Stg.h
+++ b/includes/Stg.h
@@ -49,7 +49,10 @@
# define _BSD_SOURCE
#endif
-#if IN_STG_CODE == 0
+#if IN_STG_CODE == 0 || defined(llvm_CC_FLAVOR)
+// C compilers that use an LLVM back end (clang or llvm-gcc) do not
+// correctly support global register variables so we make sure that
+// we do not declare them for these compilers.
# define NO_GLOBAL_REG_DECLS /* don't define fixed registers */
#endif
diff --git a/rts/StgCRun.c b/rts/StgCRun.c
index 7251e64253..be732d1640 100644
--- a/rts/StgCRun.c
+++ b/rts/StgCRun.c
@@ -62,13 +62,23 @@ register double fake_f9 __asm__("$f9");
#endif
#endif
+// yeuch
+#define IN_STGCRUN 1
+#ifdef sparc_HOST_ARCH
/* include Stg.h first because we want real machine regs in here: we
* have to get the value of R1 back from Stg land to C land intact.
*/
-// yeuch
-#define IN_STGCRUN 1
#include "Stg.h"
#include "Rts.h"
+#else
+/* The other architectures do not require the actual register macro
+ * definitons here because they use hand written assembly to implement
+ * the StgRun function. The sparc code could be changed so that it does
+ * not require the register macro definitions.
+ */
+#include "Rts.h"
+#include "Stg.h"
+#endif
#include "StgRun.h"
#include "Capability.h"
diff --git a/rts/Task.c b/rts/Task.c
index cf406b2abe..9e8214899c 100644
--- a/rts/Task.c
+++ b/rts/Task.c
@@ -49,6 +49,9 @@ __thread Task *my_task;
# else
ThreadLocalKey currentTaskKey;
# endif
+#ifdef llvm_CC_FLAVOR
+ThreadLocalKey gctKey;
+#endif
#else
Task *my_task;
#endif
@@ -67,6 +70,9 @@ initTaskManager (void)
#if !defined(MYTASK_USE_TLV)
newThreadLocalKey(&currentTaskKey);
#endif
+#if defined(llvm_CC_FLAVOR)
+ newThreadLocalKey(&gctKey);
+#endif
initMutex(&all_tasks_mutex);
#endif
}
@@ -96,10 +102,15 @@ freeTaskManager (void)
RELEASE_LOCK(&all_tasks_mutex);
-#if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+#if defined(THREADED_RTS)
closeMutex(&all_tasks_mutex);
+#if !defined(MYTASK_USE_TLV)
freeThreadLocalKey(&currentTaskKey);
#endif
+#if defined(llvm_CC_FLAVOR)
+ freeThreadLocalKey(&gctKey);
+#endif
+#endif
tasksInitialized = 0;
diff --git a/rts/Task.h b/rts/Task.h
index 424af607ea..4000a045d4 100644
--- a/rts/Task.h
+++ b/rts/Task.h
@@ -241,14 +241,21 @@ void interruptWorkerTask (Task *task);
// A thread-local-storage key that we can use to get access to the
// current thread's Task structure.
#if defined(THREADED_RTS)
-#if (defined(linux_HOST_OS) && \
+#if ((defined(linux_HOST_OS) && \
(defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH))) || \
- (defined(mingw32_HOST_OS) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
+ (defined(mingw32_HOST_OS) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)) && \
+ (!defined(llvm_CC_FLAVOR))
#define MYTASK_USE_TLV
extern __thread Task *my_task;
#else
extern ThreadLocalKey currentTaskKey;
#endif
+// LLVM-based compilers do not upport the __thread attribute, so we need
+// to store the gct variable as a pthread local storage. We declare the
+// key here to keep thread local storage initialization in the same place.
+#if defined(llvm_CC_FLAVOR)
+extern ThreadLocalKey gctKey;
+#endif
#else
extern Task *my_task;
#endif
diff --git a/rts/sm/GC.c b/rts/sm/GC.c
index 2252cfcd63..17d048c1fa 100644
--- a/rts/sm/GC.c
+++ b/rts/sm/GC.c
@@ -1026,7 +1026,7 @@ gcWorkerThread (Capability *cap)
// necessary if we stole a callee-saves register for gct:
saved_gct = gct;
- gct = gc_threads[cap->no];
+ SET_GCT(gc_threads[cap->no]);
gct->id = osThreadId();
stat_gcWorkerThreadStart(gct);
diff --git a/rts/sm/GCTDecl.h b/rts/sm/GCTDecl.h
index 11795ca7fd..f9c8fcb137 100644
--- a/rts/sm/GCTDecl.h
+++ b/rts/sm/GCTDecl.h
@@ -26,7 +26,11 @@
#define GLOBAL_REG_DECL(type,name,reg) register type name REG(reg);
+#ifdef llvm_CC_FLAVOR
+#define SET_GCT(to) (pthread_setspecific(gctKey, to))
+#else
#define SET_GCT(to) gct = (to)
+#endif
@@ -36,12 +40,19 @@
// about 5% in GC performance, but of course that might change as gcc
// improves. -- SDM 2009/04/03
//
-// We ought to do the same on MacOS X, but __thread is not
-// supported there yet (gcc 4.0.1).
+// For MacOSX, we can use an llvm-based C compiler which will store the gct
+// in a thread local variable using pthreads.
extern __thread gc_thread* gct;
#define DECLARE_GCT __thread gc_thread* gct;
+#elif defined(llvm_CC_FLAVOR)
+// LLVM does not support the __thread extension and will generate
+// incorrect code for global register variables. If we are compiling
+// with a C compiler that uses an LLVM back end (clang or llvm-gcc) then we
+// use pthread_getspecific() to handle the thread local storage for gct.
+#define gct ((gc_thread *)(pthread_getspecific(gctKey)))
+#define DECLARE_GCT /* nothing */
#elif defined(sparc_HOST_ARCH)
// On SPARC we can't pin gct to a register. Names like %l1 are just offsets