Merge pull request #1804 from esdrubal/processmodule
[mono.git] / mono / utils / mono-compiler.h
1 #ifndef __UTILS_MONO_COMPILER_H__
2 #define __UTILS_MONO_COMPILER_H__
3
4 /*
5  * This file includes macros used in the runtime to encapsulate different
6  * compiler behaviours.
7  */
8 #include <config.h>
9
10 #ifdef __GNUC__
11 #define MONO_ATTR_USED __attribute__ ((used))
12 #else
13 #define MONO_ATTR_USED
14 #endif
15
16 #ifdef HAVE_KW_THREAD
17
18 #define MONO_HAVE_FAST_TLS
19 #define MONO_FAST_TLS_SET(x,y) x = y
20 #define MONO_FAST_TLS_GET(x) x
21 #define MONO_FAST_TLS_INIT(x)
22 #define MONO_FAST_TLS_DECLARE(x) static __thread gpointer x MONO_TLS_FAST MONO_ATTR_USED;
23
24 #if HAVE_TLS_MODEL_ATTR
25
26 #if defined(__PIC__) && !defined(PIC)
27 /*
28  * Must be compiling -fPIE, for executables.  Build PIC
29  * but with initial-exec.
30  * http://bugs.gentoo.org/show_bug.cgi?id=165547
31  */
32 #define PIC
33 #define PIC_INITIAL_EXEC
34 #endif
35
36 /* 
37  * Define this if you want a faster libmono, which cannot be loaded dynamically as a 
38  * module.
39  */
40 //#define PIC_INITIAL_EXEC
41
42 #if defined(PIC)
43
44 #ifdef PIC_INITIAL_EXEC
45 #define MONO_TLS_FAST __attribute__((tls_model("initial-exec")))
46 #else
47 #if defined (__powerpc__)
48 /* local dynamic requires a call to __tls_get_addr to look up the
49    TLS block address via the Dynamic Thread Vector. In this case Thread
50    Pointer relative offsets can't be used as this modules TLS was
51    allocated separately (none contiguoiusly) from the initial TLS
52    block.
53
54    For now we will disable this. */
55 #define MONO_TLS_FAST
56 #else
57 #define MONO_TLS_FAST __attribute__((tls_model("local-dynamic")))
58 #endif
59 #endif
60
61 #else
62
63 #define MONO_TLS_FAST __attribute__((tls_model("local-exec")))
64
65 #endif
66
67 #else
68 #define MONO_TLS_FAST 
69 #endif
70
71 #if defined(__GNUC__) && defined(__i386__)
72 #if defined(PIC)
73 #define MONO_THREAD_VAR_OFFSET(var,offset) do { int tmp; __asm ("call 1f; 1: popl %0; addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %0; movl " #var "@gotntpoff(%0), %1" : "=r" (tmp), "=r" (offset)); } while (0)
74 #else
75 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
76 #endif
77 #elif defined(__x86_64__)
78 #if defined(PIC)
79 // This only works if libmono is linked into the application
80 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
81 #else
82 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
83 #endif
84 #elif defined(__ia64__) && !defined(__INTEL_COMPILER)
85 #if defined(PIC)
86 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("addl %0 = @ltoff(@tprel(" #var "#)), gp ;; ld8 %0 = [%0]\n" : "=r" (offset))
87 #else
88 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("addl %0 = @tprel(" #var "#), r0 ;;\n" : "=r" (offset))
89 #endif
90 #elif defined(__arm__) && defined(__ARM_EABI__) && !defined(PIC)
91 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("     ldr     %0, 1f; b 2f; 1: .word " #var "(tpoff); 2:" : "=r" (offset))
92 #elif defined(__aarch64__) && !defined(PIC)
93 #define MONO_THREAD_VAR_OFFSET(var,offset) \
94         __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
95                         : "=r" (offset))
96 #elif defined(__mono_ppc__) && defined(__GNUC__)
97 #if defined(PIC)
98 #ifdef PIC_INITIAL_EXEC
99
100 #if defined(__mono_ppc64__)
101 #define MONO_THREAD_VAR_OFFSET(var,offset) \
102         do { long off; \
103         __asm ( "ld     %0," #var "@got@tprel(2)\n" \
104         : "=r" (off)); \
105         (offset) = off; } while (0)
106 #else
107 /* must be powerpc32 */
108 #define MONO_THREAD_VAR_OFFSET(var,offset) \
109         __asm ( "lwz    %0," #var "@got@tprel(30)\n" \
110         : "=r" (offset))
111 #endif
112
113 #else
114
115 /* local dynamic requires a call to __tls_get_addr to look up the
116    TLS block address via the Dynamic Thread Vector. In this case Thread
117    Pointer relative offsets can't be used as this modules TLS was
118    allocated separately (none contiguoiusly) from the initial TLS
119    block.
120
121    For now we will disable this. */
122 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
123
124 #endif
125 #else
126 /* Must be local-exec TLS */
127 #define MONO_THREAD_VAR_OFFSET(var,offset) \
128         __asm ( "lis    %0," #var "@tprel@ha\n" \
129                 "addi   %0,%0, " #var "@tprel@l\n" \
130         : "=r" (offset))
131 #endif
132 #elif defined(__s390x__)
133 # if defined(__PIC__)
134 #  if !defined(__PIE__)
135 // This only works if libmono is linked into the application
136 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
137                                                 __asm__ ("basr  %%r1,0\n\t"                     \
138                                                          "j     0f\n\t"                         \
139                                                          ".quad " #var "@TLSGD\n"               \
140                                                          "0:\n\t"                               \
141                                                          "lg    %%r2,4(%%r1)\n\t"               \
142                                                          "brasl %%r14,__tls_get_offset@PLT:tls_gdcall:"#var"\n\t" \
143                                                          "lgr   %0,%%r2\n\t"                    \
144                                                         : "=r" (foo) :                          \
145                                                         : "1", "2", "14", "cc");                \
146                                                 offset = foo; } while (0)
147 #  elif __PIE__ == 1
148 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                         \
149                                                 __asm__ ("lg    %0," #var "@GOTNTPOFF(%%r12)\n\t"       \
150                                                          : "=r" (foo));                                 \
151                                                 offset = foo; } while (0)
152 #  elif __PIE__ == 2
153 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
154                                                 __asm__ ("larl  %%r1," #var "@INDNTPOFF\n\t"    \
155                                                          "lg    %0,0(%%r1)\n\t"                 \
156                                                          : "=r" (foo) :                         \
157                                                          : "1", "cc");                          \
158                                                 offset = foo; } while (0)
159 #  endif
160 # else
161 #  define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                          \
162                                                 __asm__ ("basr  %%r1,0\n\t"             \
163                                                          "j     0f\n\t"                 \
164                                                          ".quad " #var "@NTPOFF\n"      \
165                                                          "0:\n\t"                       \
166                                                          "lg    %0,4(%%r1)\n\t"         \
167                                                         : "=r" (foo) : : "1");          \
168                                                 offset = foo; } while (0)
169 # endif
170 #else
171 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
172 #endif
173
174 #if defined(PIC) && !defined(PIC_INITIAL_EXEC)
175 /* 
176  * The above definitions do not seem to work if libmono is loaded dynamically as a module.
177  * See bug #78767.
178  */
179 #undef MONO_THREAD_VAR_OFFSET
180 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
181 #endif
182
183 #elif defined(TARGET_MACH) && (defined(__i386__) || defined(__x86_64__))
184
185 #define MONO_HAVE_FAST_TLS
186 #define MONO_FAST_TLS_SET(x,y) pthread_setspecific(x, y)
187 #define MONO_FAST_TLS_GET(x) pthread_getspecific(x)
188 #define MONO_FAST_TLS_ADDR(x) (mono_mach_get_tls_address_from_thread (pthread_self (), x))
189 #define MONO_FAST_TLS_INIT(x) pthread_key_create(&x, NULL)
190 #define MONO_FAST_TLS_DECLARE(x) static pthread_key_t x;
191
192 #define MONO_THREAD_VAR_OFFSET(x,y) ({  \
193         __typeof__(x) _x = (x);                 \
194         pthread_key_t _y;       \
195         (void) (&_x == &_y);            \
196         y = (gint32) x; })
197 #else /* no HAVE_KW_THREAD */
198
199 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
200
201 /*Macros to facilitate user code*/
202 #define MONO_FAST_TLS_INIT(x)
203 #endif
204
205 #if defined(MONO_HAVE_FAST_TLS) && !defined(MONO_FAST_TLS_ADDR)
206 #define MONO_FAST_TLS_ADDR(x) (&(x))
207 #endif
208
209
210 /* Deal with Microsoft C compiler differences */
211 #ifdef _MSC_VER
212
213 #include <math.h>
214
215 #if _MSC_VER < 1800 /* VS 2013 */
216 #define strtoull _strtoui64
217 #endif
218
219 #include <float.h>
220 #define trunc(x)        (((x) < 0) ? ceil((x)) : floor((x)))
221 #if _MSC_VER < 1800 /* VS 2013 */
222 #define isnan(x)        _isnan(x)
223 #define isinf(x)        (_isnan(x) ? 0 : (_fpclass(x) == _FPCLASS_NINF) ? -1 : (_fpclass(x) == _FPCLASS_PINF) ? 1 : 0)
224 #define isnormal(x)     _finite(x)
225 #endif
226
227 #define popen           _popen
228 #define pclose          _pclose
229
230 #include <direct.h>
231 #define mkdir(x)        _mkdir(x)
232
233 /* GCC specific functions aren't available */
234 #define __builtin_return_address(x)     NULL
235
236 #define __func__ __FUNCTION__
237
238 #include <BaseTsd.h>
239 typedef SSIZE_T ssize_t;
240
241 /*
242  * SSIZE_MAX is not defined in MSVC, so define it here.
243  *
244  * These values come from MinGW64, and are public domain.
245  *
246  */
247 #ifndef SSIZE_MAX
248 #ifdef _WIN64
249 #define SSIZE_MAX _I64_MAX
250 #else
251 #define SSIZE_MAX INT_MAX
252 #endif
253 #endif
254
255 #endif /* _MSC_VER */
256
257 #if !defined(_MSC_VER) && !defined(PLATFORM_SOLARIS) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MONOTOUCH) && HAVE_VISIBILITY_HIDDEN
258 #if MONO_LLVM_LOADED
259 #define MONO_LLVM_INTERNAL MONO_API
260 #else
261 #define MONO_LLVM_INTERNAL
262 #endif
263 #else
264 #define MONO_LLVM_INTERNAL 
265 #endif
266
267 #if HAVE_DEPRECATED
268 #define MONO_DEPRECATED __attribute__ ((deprecated))
269 #else
270 #define MONO_DEPRECATED 
271 #endif
272
273 #ifdef __GNUC__
274 #define MONO_ALWAYS_INLINE __attribute__((always_inline))
275 #elif defined(_MSC_VER)
276 #define MONO_ALWAYS_INLINE __forceinline
277 #else
278 #define MONO_ALWAYS_INLINE
279 #endif
280
281 #ifdef __GNUC__
282 #define MONO_NEVER_INLINE __attribute__((noinline))
283 #elif defined(_MSC_VER)
284 #define MONO_NEVER_INLINE __declspec(noinline)
285 #else
286 #define MONO_NEVER_INLINE
287 #endif
288
289 #ifdef __GNUC__
290 #define MONO_COLD __attribute__((cold))
291 #else
292 #define MONO_COLD
293 #endif
294
295 #endif /* __UTILS_MONO_COMPILER_H__*/
296