Contributed under the terms of the MIT/X11 license by
[mono.git] / mono / mini / mini-amd64.h
1 #ifndef __MONO_MINI_AMD64_H__
2 #define __MONO_MINI_AMD64_H__
3
4 #include <mono/arch/amd64/amd64-codegen.h>
5 #include <glib.h>
6
7 #ifdef PLATFORM_WIN32
8 #include <windows.h>
9 /* use SIG* defines if possible */
10 #ifdef HAVE_SIGNAL_H
11 #include <signal.h>
12 #endif
13
14 /* sigcontext surrogate */
15 struct sigcontext {
16         guint64 eax;
17         guint64 ebx;
18         guint64 ecx;
19         guint64 edx;
20         guint64 ebp;
21         guint64 esp;
22     guint64 esi;
23         guint64 edi;
24         guint64 eip;
25 };
26
27 typedef void (* MonoW32ExceptionHandler) (int);
28 void win32_seh_init(void);
29 void win32_seh_cleanup(void);
30 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
31
32 #ifndef SIGFPE
33 #define SIGFPE 4
34 #endif
35
36 #ifndef SIGILL
37 #define SIGILL 8
38 #endif
39
40 #ifndef SIGSEGV
41 #define SIGSEGV 11
42 #endif
43
44 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
45
46 #endif /* PLATFORM_WIN32 */
47
48 #ifdef sun    // Solaris x86
49 #  undef SIGSEGV_ON_ALTSTACK
50 #  define MONO_ARCH_NOMAP32BIT
51
52 struct sigcontext {
53         unsigned short gs, __gsh;
54         unsigned short fs, __fsh;
55         unsigned short es, __esh;
56         unsigned short ds, __dsh;
57         unsigned long edi;
58         unsigned long esi;
59         unsigned long ebp;
60         unsigned long esp;
61         unsigned long ebx;
62         unsigned long edx;
63         unsigned long ecx;
64         unsigned long eax;
65         unsigned long trapno;
66         unsigned long err;
67         unsigned long eip;
68         unsigned short cs, __csh;
69         unsigned long eflags;
70         unsigned long esp_at_signal;
71         unsigned short ss, __ssh;
72         unsigned long fpstate[95];
73       unsigned long filler[5];
74 };
75 #endif  // sun, Solaris x86
76
77 #define MONO_ARCH_SUPPORT_SIMD_INTRINSICS 1
78
79 #ifndef DISABLE_SIMD
80 #define MONO_ARCH_SIMD_INTRINSICS 1
81 #define MONO_ARCH_NEED_SIMD_BANK 1
82 #endif
83
84
85
86 #define MONO_ARCH_SIGNAL_STACK_SIZE (16 * 1024)
87
88 #define MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT 1
89
90 #define MONO_ARCH_CPU_SPEC amd64_desc
91
92 #define MONO_MAX_IREGS 16
93
94 #define MONO_MAX_FREGS AMD64_XMM_NREG
95
96 #define MONO_ARCH_FP_RETURN_REG AMD64_XMM0
97
98 /* XREG and FREG banks are the same in amd64 
99  * Until the regalloc is redone so that they can play nicely
100  * divide up the regbank and force them to play in thier own worlds.
101  *
102  * FREGS are at the top of the xmm reg bank and the XREGS are at the bottom.
103  */
104 /* xmm15 is reserved for use by some opcodes */
105 #define MONO_ARCH_CALLEE_FREGS 0x00ff
106 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
107
108 #define MONO_MAX_XREGS MONO_MAX_FREGS
109
110 #define MONO_ARCH_CALLEE_XREGS 0x7f00
111 #define MONO_ARCH_CALLEE_SAVED_XREGS 0
112
113
114 #define MONO_ARCH_CALLEE_REGS AMD64_CALLEE_REGS
115 #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS
116
117 #define MONO_ARCH_USE_FPSTACK FALSE
118 #define MONO_ARCH_FPSTACK_SIZE 0
119
120 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == '\0') ? -1 : ((desc == 'i' ? -1 : ((desc == 'a') ? AMD64_RAX : ((desc == 's') ? AMD64_RCX : ((desc == 'd') ? AMD64_RDX : -1))))))
121
122 /* RDX is clobbered by the opcode implementation before accessing sreg2 */
123 #define MONO_ARCH_INST_SREG2_MASK(ins) (((ins [MONO_INST_CLOB] == 'a') || (ins [MONO_INST_CLOB] == 'd')) ? (1 << AMD64_RDX) : 0)
124
125 #define MONO_ARCH_INST_IS_REGPAIR(desc) FALSE
126 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
127
128 #define MONO_ARCH_FRAME_ALIGNMENT 16
129
130 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get 
131  * reproduceable results for benchmarks */
132 #define MONO_ARCH_CODE_ALIGNMENT 32
133
134 #define MONO_ARCH_RETREG1 X86_EAX
135 #define MONO_ARCH_RETREG2 X86_EDX
136
137 struct MonoLMF {
138         /* 
139          * If the lowest bit is set to 1, then this LMF has the rip field set. Otherwise,
140          * the rip field is not set, and the rsp field points to the stack location where
141          * the caller ip is saved.
142          */
143         gpointer    previous_lmf;
144         gpointer    lmf_addr;
145         /* This is only set in trampoline LMF frames */
146         MonoMethod *method;
147         guint64     rip;
148         guint64     rbx;
149         guint64     rbp;
150         guint64     rsp;
151         guint64     r12;
152         guint64     r13;
153         guint64     r14;
154         guint64     r15;
155 #ifdef PLATFORM_WIN32
156         guint64     rdi;
157         guint64     rsi;
158 #endif
159 };
160
161 typedef struct MonoCompileArch {
162         gint32 lmf_offset;
163         gint32 localloc_offset;
164         gint32 reg_save_area_offset;
165         gint32 stack_alloc_size;
166         gboolean omit_fp, omit_fp_computed, no_pushes;
167         gpointer cinfo;
168         gint32 async_point_count;
169         gpointer vret_addr_loc;
170 #ifdef PLATFORM_WIN32
171         gpointer        unwindinfo;
172 #endif
173 } MonoCompileArch;
174
175 typedef struct {
176         guint64 rax;
177         guint64 rbx;
178         guint64 rcx;
179         guint64 rdx;
180         guint64 rbp;
181         guint64 rsp;
182     guint64 rsi;
183         guint64 rdi;
184         guint64 rip;
185         guint64 r12;
186         guint64 r13;
187         guint64 r14;
188         guint64 r15;
189 } MonoContext;
190
191 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->rip = (guint64)(ip); } while (0); 
192 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->rbp = (guint64)(bp); } while (0); 
193 #define MONO_CONTEXT_SET_SP(ctx,esp) do { (ctx)->rsp = (guint64)(esp); } while (0); 
194
195 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->rip))
196 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->rbp))
197 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->rsp))
198
199 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
200
201 #ifdef _MSC_VER
202
203 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
204     guint64 stackptr; \
205         mono_arch_flush_register_windows (); \
206         stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
207         MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
208         MONO_CONTEXT_SET_BP ((ctx), stackptr); \
209         MONO_CONTEXT_SET_SP ((ctx), stackptr); \
210 } while (0)
211
212 #else
213
214 /* 
215  * __builtin_frame_address () is broken on some older gcc versions in the presence of
216  * frame pointer elimination, see bug #82095.
217  */
218 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do {        \
219         int tmp; \
220         guint64 stackptr = (guint64)&tmp; \
221                 mono_arch_flush_register_windows ();    \
222                 MONO_CONTEXT_SET_IP ((ctx), (start_func));      \
223                 MONO_CONTEXT_SET_BP ((ctx), stackptr);  \
224                 MONO_CONTEXT_SET_SP ((ctx), stackptr);  \
225         } while (0)
226
227 #endif
228
229 /*
230  * some icalls like mono_array_new_va needs to be called using a different 
231  * calling convention.
232  */
233 #define MONO_ARCH_VARARG_ICALLS 1
234
235 #ifndef PLATFORM_WIN32
236
237 #define MONO_ARCH_USE_SIGACTION 1
238
239 #ifdef HAVE_WORKING_SIGALTSTACK
240
241 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
242
243 #endif
244
245 #ifdef __OpenBSD__
246 #undef MONO_ARCH_USE_SIGACTION
247 #endif
248
249 #endif /* PLATFORM_WIN32 */
250
251 #if defined (__NetBSD__)
252
253 #define REG_RAX 14
254 #define REG_RCX 3
255 #define REG_RDX 2
256 #define REG_RBX 13
257 #define REG_RSP 24
258 #define REG_RBP 12
259 #define REG_RSI 1
260 #define REG_RDI 0
261 #define REG_R8 4
262 #define REG_R9 5
263 #define REG_R10 6
264 #define REG_R11 7
265 #define REG_R12 8
266 #define REG_R13 9
267 #define REG_R14 10
268 #define REG_R15 11
269 #define REG_RIP 21
270
271 #define MONO_ARCH_NOMAP32BIT
272
273 #elif defined (__FreeBSD__) || defined (__OpenBSD__)
274
275 #define REG_RAX 7
276 #define REG_RCX 4
277 #define REG_RDX 3
278 #define REG_RBX 8
279 #define REG_RSP 23
280 #define REG_RBP 9
281 #define REG_RSI 2
282 #define REG_RDI 1
283 #define REG_R8  5
284 #define REG_R9  6
285 #define REG_R10 10
286 #define REG_R11 11
287 #define REG_R12 12
288 #define REG_R13 13
289 #define REG_R14 14
290 #define REG_R15 15
291 #define REG_RIP 20
292
293 /* 
294  * FreeBSD does not have MAP_32BIT, so code allocated by the code manager might not have a
295  * 32 bit address.
296  */
297 #define MONO_ARCH_NOMAP32BIT
298
299 #endif /* __FreeBSD__ */
300
301 #ifdef PLATFORM_WIN32
302 #define MONO_AMD64_ARG_REG1 AMD64_RCX
303 #define MONO_AMD64_ARG_REG2 AMD64_RDX
304 #else
305 #define MONO_AMD64_ARG_REG1 AMD64_RDI
306 #define MONO_AMD64_ARG_REG2 AMD64_RSI
307 #endif
308
309 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
310 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
311
312 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
313 #define MONO_ARCH_EMULATE_FREM 1
314 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
315
316 #define MONO_ARCH_ENABLE_REGALLOC_IN_EH_BLOCKS 1
317 #define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
318 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
319 #define MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION 1
320 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
321 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
322 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
323 #define MONO_ARCH_HAVE_ATOMIC_CAS 1
324 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
325 #define MONO_ARCH_HAVE_IMT 1
326 #define MONO_ARCH_HAVE_TLS_GET 1
327 #define MONO_ARCH_IMT_REG AMD64_R11
328 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
329 /*
330  * We use r10 for the rgctx register rather than r11 because r11 is
331  * used by the trampoline as a scratch register and hence might be
332  * clobbered across method call boundaries.
333  */
334 #define MONO_ARCH_RGCTX_REG AMD64_R10
335 #define MONO_ARCH_HAVE_CMOV_OPS 1
336 #define MONO_ARCH_HAVE_NOTIFY_PENDING_EXC 1
337 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
338 #define MONO_ARCH_ENABLE_GLOBAL_RA 1
339 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
340 #define MONO_ARCH_HAVE_LIVERANGE_OPS 1
341 #define MONO_ARCH_HAVE_XP_UNWIND 1
342 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
343 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
344 #define MONO_ARCH_MONITOR_OBJECT_REG AMD64_RDI
345 #endif
346 #define MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE 1
347
348 #define MONO_ARCH_AOT_SUPPORTED 1
349
350 #if !defined(PLATFORM_WIN32) || defined(__sun)
351 #define MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH 1
352 #endif
353
354 #define MONO_ARCH_SUPPORT_TASKLETS 1
355
356 #ifndef PLATFORM_WIN32
357 #define MONO_AMD64_NO_PUSHES 1
358 #endif
359
360 #define MONO_ARCH_GSHARED_SUPPORTED 1
361
362 #define MONO_ARCH_USE_OP_TAIL_CALL(caller_sig, callee_sig) mono_metadata_signature_equal ((caller_sig), (callee_sig))
363
364 /* Used for optimization, not complete */
365 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
366
367 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
368             MonoInst *inst; \
369             MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
370             inst->inst_basereg = array_reg; \
371             inst->inst_offset = offset; \
372             inst->sreg2 = index_reg; \
373             MONO_ADD_INS ((cfg)->cbb, inst); \
374             MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
375        } while (0)
376
377 void 
378 mono_amd64_patch (unsigned char* code, gpointer target) MONO_INTERNAL;
379
380 void
381 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
382                                                         guint64 dummy5, guint64 dummy6,
383                                                         MonoObject *exc, guint64 rip, guint64 rsp,
384                                                         guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
385                                                         guint64 r14, guint64 r15, guint64 rdi, guint64 rsi, 
386                                                         guint64 rax, guint64 rcx, guint64 rdx,
387                                                         guint64 rethrow);
388
389 guint64
390 mono_amd64_get_original_ip (void) MONO_INTERNAL;
391
392 guint8*
393 mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset) MONO_INTERNAL;
394
395 typedef struct {
396         guint8 *address;
397         guint8 saved_byte;
398 } MonoBreakpointInfo;
399
400 extern MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
401
402 #ifdef PLATFORM_WIN32
403
404 void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
405 void mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
406 void mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size );
407 guint mono_arch_unwindinfo_get_size (gpointer monoui);
408 void mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size);
409
410 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
411 #endif
412
413 #endif /* __MONO_MINI_AMD64_H__ */  
414