e5ac990f7a9aa4152bcd0bc0adc82eefc7ddb559
[mono.git] / mono / mini / mini-x86.c
1 /*
2  * mini-x86.c: x86 backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Patrik Torstensson
8  *
9  * (C) 2003 Ximian, Inc.
10  */
11 #include "mini.h"
12 #include <string.h>
13 #include <math.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/mono-debug.h>
23 #include <mono/utils/mono-math.h>
24 #include <mono/utils/mono-counters.h>
25 #include <mono/utils/mono-mmap.h>
26
27 #include "trace.h"
28 #include "mini-x86.h"
29 #include "cpu-x86.h"
30 #include "ir-emit.h"
31
32 /* On windows, these hold the key returned by TlsAlloc () */
33 static gint lmf_tls_offset = -1;
34 static gint lmf_addr_tls_offset = -1;
35 static gint appdomain_tls_offset = -1;
36
37 #ifdef MONO_XEN_OPT
38 static gboolean optimize_for_xen = TRUE;
39 #else
40 #define optimize_for_xen 0
41 #endif
42
43 #ifdef PLATFORM_WIN32
44 static gboolean is_win32 = TRUE;
45 #else
46 static gboolean is_win32 = FALSE;
47 #endif
48
49 /* This mutex protects architecture specific caches */
50 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
51 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
52 static CRITICAL_SECTION mini_arch_mutex;
53
54 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
55
56 #define ARGS_OFFSET 8
57
58 #ifdef PLATFORM_WIN32
59 /* Under windows, the default pinvoke calling convention is stdcall */
60 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
61 #else
62 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
63 #endif
64
65 MonoBreakpointInfo
66 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
67
68 /*
69  * The code generated for sequence points reads from this location, which is
70  * made read-only when single stepping is enabled.
71  */
72 static gpointer ss_trigger_page;
73
74 /* Enabled breakpoints read from this trigger page */
75 static gpointer bp_trigger_page;
76
77 const char*
78 mono_arch_regname (int reg)
79 {
80         switch (reg) {
81         case X86_EAX: return "%eax";
82         case X86_EBX: return "%ebx";
83         case X86_ECX: return "%ecx";
84         case X86_EDX: return "%edx";
85         case X86_ESP: return "%esp";    
86         case X86_EBP: return "%ebp";
87         case X86_EDI: return "%edi";
88         case X86_ESI: return "%esi";
89         }
90         return "unknown";
91 }
92
93 const char*
94 mono_arch_fregname (int reg)
95 {
96         switch (reg) {
97         case 0:
98                 return "%fr0";
99         case 1:
100                 return "%fr1";
101         case 2:
102                 return "%fr2";
103         case 3:
104                 return "%fr3";
105         case 4:
106                 return "%fr4";
107         case 5:
108                 return "%fr5";
109         case 6:
110                 return "%fr6";
111         case 7:
112                 return "%fr7";
113         default:
114                 return "unknown";
115         }
116 }
117
118 const char *
119 mono_arch_xregname (int reg)
120 {
121         switch (reg) {
122         case 0:
123                 return "%xmm0";
124         case 1:
125                 return "%xmm1";
126         case 2:
127                 return "%xmm2";
128         case 3:
129                 return "%xmm3";
130         case 4:
131                 return "%xmm4";
132         case 5:
133                 return "%xmm5";
134         case 6:
135                 return "%xmm6";
136         case 7:
137                 return "%xmm7";
138         default:
139                 return "unknown";
140         }
141 }
142
143
144 typedef enum {
145         ArgInIReg,
146         ArgInFloatSSEReg,
147         ArgInDoubleSSEReg,
148         ArgOnStack,
149         ArgValuetypeInReg,
150         ArgOnFloatFpStack,
151         ArgOnDoubleFpStack,
152         ArgNone
153 } ArgStorage;
154
155 typedef struct {
156         gint16 offset;
157         gint8  reg;
158         ArgStorage storage;
159
160         /* Only if storage == ArgValuetypeInReg */
161         ArgStorage pair_storage [2];
162         gint8 pair_regs [2];
163 } ArgInfo;
164
165 typedef struct {
166         int nargs;
167         guint32 stack_usage;
168         guint32 reg_usage;
169         guint32 freg_usage;
170         gboolean need_stack_align;
171         guint32 stack_align_amount;
172         ArgInfo ret;
173         ArgInfo sig_cookie;
174         ArgInfo args [1];
175 } CallInfo;
176
177 #define PARAM_REGS 0
178
179 #define FLOAT_PARAM_REGS 0
180
181 static X86_Reg_No param_regs [] = { 0 };
182
183 #if defined(PLATFORM_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
184 #define SMALL_STRUCTS_IN_REGS
185 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
186 #endif
187
188 static void inline
189 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
190 {
191     ainfo->offset = *stack_size;
192
193     if (*gr >= PARAM_REGS) {
194                 ainfo->storage = ArgOnStack;
195                 (*stack_size) += sizeof (gpointer);
196     }
197     else {
198                 ainfo->storage = ArgInIReg;
199                 ainfo->reg = param_regs [*gr];
200                 (*gr) ++;
201     }
202 }
203
204 static void inline
205 add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
206 {
207         ainfo->offset = *stack_size;
208
209         g_assert (PARAM_REGS == 0);
210         
211         ainfo->storage = ArgOnStack;
212         (*stack_size) += sizeof (gpointer) * 2;
213 }
214
215 static void inline
216 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
217 {
218     ainfo->offset = *stack_size;
219
220     if (*gr >= FLOAT_PARAM_REGS) {
221                 ainfo->storage = ArgOnStack;
222                 (*stack_size) += is_double ? 8 : 4;
223     }
224     else {
225                 /* A double register */
226                 if (is_double)
227                         ainfo->storage = ArgInDoubleSSEReg;
228                 else
229                         ainfo->storage = ArgInFloatSSEReg;
230                 ainfo->reg = *gr;
231                 (*gr) += 1;
232     }
233 }
234
235
236 static void
237 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
238                gboolean is_return,
239                guint32 *gr, guint32 *fr, guint32 *stack_size)
240 {
241         guint32 size;
242         MonoClass *klass;
243
244         klass = mono_class_from_mono_type (type);
245         size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
246
247 #ifdef SMALL_STRUCTS_IN_REGS
248         if (sig->pinvoke && is_return) {
249                 MonoMarshalType *info;
250
251                 /*
252                  * the exact rules are not very well documented, the code below seems to work with the 
253                  * code generated by gcc 3.3.3 -mno-cygwin.
254                  */
255                 info = mono_marshal_load_type_info (klass);
256                 g_assert (info);
257
258                 ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
259
260                 /* Special case structs with only a float member */
261                 if ((info->native_size == 8) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R8)) {
262                         ainfo->storage = ArgValuetypeInReg;
263                         ainfo->pair_storage [0] = ArgOnDoubleFpStack;
264                         return;
265                 }
266                 if ((info->native_size == 4) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R4)) {
267                         ainfo->storage = ArgValuetypeInReg;
268                         ainfo->pair_storage [0] = ArgOnFloatFpStack;
269                         return;
270                 }               
271                 if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
272                         ainfo->storage = ArgValuetypeInReg;
273                         ainfo->pair_storage [0] = ArgInIReg;
274                         ainfo->pair_regs [0] = return_regs [0];
275                         if (info->native_size > 4) {
276                                 ainfo->pair_storage [1] = ArgInIReg;
277                                 ainfo->pair_regs [1] = return_regs [1];
278                         }
279                         return;
280                 }
281         }
282 #endif
283
284         ainfo->offset = *stack_size;
285         ainfo->storage = ArgOnStack;
286         *stack_size += ALIGN_TO (size, sizeof (gpointer));
287 }
288
289 /*
290  * get_call_info:
291  *
292  *  Obtain information about a call according to the calling convention.
293  * For x86 ELF, see the "System V Application Binary Interface Intel386 
294  * Architecture Processor Supplment, Fourth Edition" document for more
295  * information.
296  * For x86 win32, see ???.
297  */
298 static CallInfo*
299 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
300 {
301         guint32 i, gr, fr;
302         MonoType *ret_type;
303         int n = sig->hasthis + sig->param_count;
304         guint32 stack_size = 0;
305         CallInfo *cinfo;
306
307         if (mp)
308                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
309         else
310                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
311
312         gr = 0;
313         fr = 0;
314
315         /* return value */
316         {
317                 ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
318                 switch (ret_type->type) {
319                 case MONO_TYPE_BOOLEAN:
320                 case MONO_TYPE_I1:
321                 case MONO_TYPE_U1:
322                 case MONO_TYPE_I2:
323                 case MONO_TYPE_U2:
324                 case MONO_TYPE_CHAR:
325                 case MONO_TYPE_I4:
326                 case MONO_TYPE_U4:
327                 case MONO_TYPE_I:
328                 case MONO_TYPE_U:
329                 case MONO_TYPE_PTR:
330                 case MONO_TYPE_FNPTR:
331                 case MONO_TYPE_CLASS:
332                 case MONO_TYPE_OBJECT:
333                 case MONO_TYPE_SZARRAY:
334                 case MONO_TYPE_ARRAY:
335                 case MONO_TYPE_STRING:
336                         cinfo->ret.storage = ArgInIReg;
337                         cinfo->ret.reg = X86_EAX;
338                         break;
339                 case MONO_TYPE_U8:
340                 case MONO_TYPE_I8:
341                         cinfo->ret.storage = ArgInIReg;
342                         cinfo->ret.reg = X86_EAX;
343                         break;
344                 case MONO_TYPE_R4:
345                         cinfo->ret.storage = ArgOnFloatFpStack;
346                         break;
347                 case MONO_TYPE_R8:
348                         cinfo->ret.storage = ArgOnDoubleFpStack;
349                         break;
350                 case MONO_TYPE_GENERICINST:
351                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
352                                 cinfo->ret.storage = ArgInIReg;
353                                 cinfo->ret.reg = X86_EAX;
354                                 break;
355                         }
356                         /* Fall through */
357                 case MONO_TYPE_VALUETYPE: {
358                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
359
360                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
361                         if (cinfo->ret.storage == ArgOnStack)
362                                 /* The caller passes the address where the value is stored */
363                                 add_general (&gr, &stack_size, &cinfo->ret);
364                         break;
365                 }
366                 case MONO_TYPE_TYPEDBYREF:
367                         /* Same as a valuetype with size 24 */
368                         add_general (&gr, &stack_size, &cinfo->ret);
369                         ;
370                         break;
371                 case MONO_TYPE_VOID:
372                         cinfo->ret.storage = ArgNone;
373                         break;
374                 default:
375                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
376                 }
377         }
378
379         /* this */
380         if (sig->hasthis)
381                 add_general (&gr, &stack_size, cinfo->args + 0);
382
383         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
384                 gr = PARAM_REGS;
385                 fr = FLOAT_PARAM_REGS;
386                 
387                 /* Emit the signature cookie just before the implicit arguments */
388                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
389         }
390
391         for (i = 0; i < sig->param_count; ++i) {
392                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
393                 MonoType *ptype;
394
395                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
396                         /* We allways pass the sig cookie on the stack for simplicity */
397                         /* 
398                          * Prevent implicit arguments + the sig cookie from being passed 
399                          * in registers.
400                          */
401                         gr = PARAM_REGS;
402                         fr = FLOAT_PARAM_REGS;
403
404                         /* Emit the signature cookie just before the implicit arguments */
405                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
406                 }
407
408                 if (sig->params [i]->byref) {
409                         add_general (&gr, &stack_size, ainfo);
410                         continue;
411                 }
412                 ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
413                 switch (ptype->type) {
414                 case MONO_TYPE_BOOLEAN:
415                 case MONO_TYPE_I1:
416                 case MONO_TYPE_U1:
417                         add_general (&gr, &stack_size, ainfo);
418                         break;
419                 case MONO_TYPE_I2:
420                 case MONO_TYPE_U2:
421                 case MONO_TYPE_CHAR:
422                         add_general (&gr, &stack_size, ainfo);
423                         break;
424                 case MONO_TYPE_I4:
425                 case MONO_TYPE_U4:
426                         add_general (&gr, &stack_size, ainfo);
427                         break;
428                 case MONO_TYPE_I:
429                 case MONO_TYPE_U:
430                 case MONO_TYPE_PTR:
431                 case MONO_TYPE_FNPTR:
432                 case MONO_TYPE_CLASS:
433                 case MONO_TYPE_OBJECT:
434                 case MONO_TYPE_STRING:
435                 case MONO_TYPE_SZARRAY:
436                 case MONO_TYPE_ARRAY:
437                         add_general (&gr, &stack_size, ainfo);
438                         break;
439                 case MONO_TYPE_GENERICINST:
440                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
441                                 add_general (&gr, &stack_size, ainfo);
442                                 break;
443                         }
444                         /* Fall through */
445                 case MONO_TYPE_VALUETYPE:
446                         add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
447                         break;
448                 case MONO_TYPE_TYPEDBYREF:
449                         stack_size += sizeof (MonoTypedRef);
450                         ainfo->storage = ArgOnStack;
451                         break;
452                 case MONO_TYPE_U8:
453                 case MONO_TYPE_I8:
454                         add_general_pair (&gr, &stack_size, ainfo);
455                         break;
456                 case MONO_TYPE_R4:
457                         add_float (&fr, &stack_size, ainfo, FALSE);
458                         break;
459                 case MONO_TYPE_R8:
460                         add_float (&fr, &stack_size, ainfo, TRUE);
461                         break;
462                 default:
463                         g_error ("unexpected type 0x%x", ptype->type);
464                         g_assert_not_reached ();
465                 }
466         }
467
468         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
469                 gr = PARAM_REGS;
470                 fr = FLOAT_PARAM_REGS;
471                 
472                 /* Emit the signature cookie just before the implicit arguments */
473                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
474         }
475
476         if (mono_do_x86_stack_align && (stack_size % MONO_ARCH_FRAME_ALIGNMENT) != 0) {
477                 cinfo->need_stack_align = TRUE;
478                 cinfo->stack_align_amount = MONO_ARCH_FRAME_ALIGNMENT - (stack_size % MONO_ARCH_FRAME_ALIGNMENT);
479                 stack_size += cinfo->stack_align_amount;
480         }
481
482         cinfo->stack_usage = stack_size;
483         cinfo->reg_usage = gr;
484         cinfo->freg_usage = fr;
485         return cinfo;
486 }
487
488 /*
489  * mono_arch_get_argument_info:
490  * @csig:  a method signature
491  * @param_count: the number of parameters to consider
492  * @arg_info: an array to store the result infos
493  *
494  * Gathers information on parameters such as size, alignment and
495  * padding. arg_info should be large enought to hold param_count + 1 entries. 
496  *
497  * Returns the size of the argument area on the stack.
498  */
499 int
500 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
501 {
502         int k, args_size = 0;
503         int size, pad;
504         guint32 align;
505         int offset = 8;
506         CallInfo *cinfo;
507
508         cinfo = get_call_info (NULL, NULL, csig, FALSE);
509
510         if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
511                 args_size += sizeof (gpointer);
512                 offset += 4;
513         }
514
515         arg_info [0].offset = offset;
516
517         if (csig->hasthis) {
518                 args_size += sizeof (gpointer);
519                 offset += 4;
520         }
521
522         arg_info [0].size = args_size;
523
524         for (k = 0; k < param_count; k++) {
525                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
526
527                 /* ignore alignment for now */
528                 align = 1;
529
530                 args_size += pad = (align - (args_size & (align - 1))) & (align - 1);   
531                 arg_info [k].pad = pad;
532                 args_size += size;
533                 arg_info [k + 1].pad = 0;
534                 arg_info [k + 1].size = size;
535                 offset += pad;
536                 arg_info [k + 1].offset = offset;
537                 offset += size;
538         }
539
540         if (mono_do_x86_stack_align && !CALLCONV_IS_STDCALL (csig))
541                 align = MONO_ARCH_FRAME_ALIGNMENT;
542         else
543                 align = 4;
544         args_size += pad = (align - (args_size & (align - 1))) & (align - 1);
545         arg_info [k].pad = pad;
546
547         g_free (cinfo);
548
549         return args_size;
550 }
551
552 static const guchar cpuid_impl [] = {
553         0x55,                           /* push   %ebp */
554         0x89, 0xe5,                     /* mov    %esp,%ebp */
555         0x53,                           /* push   %ebx */
556         0x8b, 0x45, 0x08,               /* mov    0x8(%ebp),%eax */
557         0x0f, 0xa2,                     /* cpuid   */
558         0x50,                           /* push   %eax */
559         0x8b, 0x45, 0x10,               /* mov    0x10(%ebp),%eax */
560         0x89, 0x18,                     /* mov    %ebx,(%eax) */
561         0x8b, 0x45, 0x14,               /* mov    0x14(%ebp),%eax */
562         0x89, 0x08,                     /* mov    %ecx,(%eax) */
563         0x8b, 0x45, 0x18,               /* mov    0x18(%ebp),%eax */
564         0x89, 0x10,                     /* mov    %edx,(%eax) */
565         0x58,                           /* pop    %eax */
566         0x8b, 0x55, 0x0c,               /* mov    0xc(%ebp),%edx */
567         0x89, 0x02,                     /* mov    %eax,(%edx) */
568         0x5b,                           /* pop    %ebx */
569         0xc9,                           /* leave   */
570         0xc3,                           /* ret     */
571 };
572
573 typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx);
574
575 static int 
576 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
577 {
578         int have_cpuid = 0;
579 #ifndef _MSC_VER
580         __asm__  __volatile__ (
581                 "pushfl\n"
582                 "popl %%eax\n"
583                 "movl %%eax, %%edx\n"
584                 "xorl $0x200000, %%eax\n"
585                 "pushl %%eax\n"
586                 "popfl\n"
587                 "pushfl\n"
588                 "popl %%eax\n"
589                 "xorl %%edx, %%eax\n"
590                 "andl $0x200000, %%eax\n"
591                 "movl %%eax, %0"
592                 : "=r" (have_cpuid)
593                 :
594                 : "%eax", "%edx"
595         );
596 #else
597         __asm {
598                 pushfd
599                 pop eax
600                 mov edx, eax
601                 xor eax, 0x200000
602                 push eax
603                 popfd
604                 pushfd
605                 pop eax
606                 xor eax, edx
607                 and eax, 0x200000
608                 mov have_cpuid, eax
609         }
610 #endif
611         if (have_cpuid) {
612                 /* Have to use the code manager to get around WinXP DEP */
613                 static CpuidFunc func = NULL;
614                 void *ptr;
615                 if (!func) {
616                         ptr = mono_global_codeman_reserve (sizeof (cpuid_impl));
617                         memcpy (ptr, cpuid_impl, sizeof (cpuid_impl));
618                         func = (CpuidFunc)ptr;
619                 }
620                 func (id, p_eax, p_ebx, p_ecx, p_edx);
621
622                 /*
623                  * We use this approach because of issues with gcc and pic code, see:
624                  * http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=7329
625                 __asm__ __volatile__ ("cpuid"
626                         : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
627                         : "a" (id));
628                 */
629                 return 1;
630         }
631         return 0;
632 }
633
634 /*
635  * Initialize the cpu to execute managed code.
636  */
637 void
638 mono_arch_cpu_init (void)
639 {
640         /* spec compliance requires running with double precision */
641 #ifndef _MSC_VER
642         guint16 fpcw;
643
644         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
645         fpcw &= ~X86_FPCW_PRECC_MASK;
646         fpcw |= X86_FPCW_PREC_DOUBLE;
647         __asm__  __volatile__ ("fldcw %0\n": : "m" (fpcw));
648         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
649 #else
650         _control87 (_PC_53, MCW_PC);
651 #endif
652 }
653
654 /*
655  * Initialize architecture specific code.
656  */
657 void
658 mono_arch_init (void)
659 {
660         InitializeCriticalSection (&mini_arch_mutex);
661
662         ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
663         bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
664         mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
665 }
666
667 /*
668  * Cleanup architecture specific code.
669  */
670 void
671 mono_arch_cleanup (void)
672 {
673         DeleteCriticalSection (&mini_arch_mutex);
674 }
675
676 /*
677  * This function returns the optimizations supported on this cpu.
678  */
679 guint32
680 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
681 {
682         int eax, ebx, ecx, edx;
683         guint32 opts = 0;
684         
685         *exclude_mask = 0;
686         /* Feature Flags function, flags returned in EDX. */
687         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
688                 if (edx & (1 << 15)) {
689                         opts |= MONO_OPT_CMOV;
690                         if (edx & 1)
691                                 opts |= MONO_OPT_FCMOV;
692                         else
693                                 *exclude_mask |= MONO_OPT_FCMOV;
694                 } else
695                         *exclude_mask |= MONO_OPT_CMOV;
696                 if (edx & (1 << 26))
697                         opts |= MONO_OPT_SSE2;
698                 else
699                         *exclude_mask |= MONO_OPT_SSE2;
700
701 #ifdef MONO_ARCH_SIMD_INTRINSICS
702                 /*SIMD intrinsics require at least SSE2.*/
703                 if (!(opts & MONO_OPT_SSE2))
704                         *exclude_mask |= MONO_OPT_SIMD;
705 #endif
706         }
707         return opts;
708 }
709
710 /*
711  * This function test for all SSE functions supported.
712  *
713  * Returns a bitmask corresponding to all supported versions.
714  * 
715  */
716 guint32
717 mono_arch_cpu_enumerate_simd_versions (void)
718 {
719         int eax, ebx, ecx, edx;
720         guint32 sse_opts = 0;
721
722         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
723                 if (edx & (1 << 25))
724                         sse_opts |= 1 << SIMD_VERSION_SSE1;
725                 if (edx & (1 << 26))
726                         sse_opts |= 1 << SIMD_VERSION_SSE2;
727                 if (ecx & (1 << 0))
728                         sse_opts |= 1 << SIMD_VERSION_SSE3;
729                 if (ecx & (1 << 9))
730                         sse_opts |= 1 << SIMD_VERSION_SSSE3;
731                 if (ecx & (1 << 19))
732                         sse_opts |= 1 << SIMD_VERSION_SSE41;
733                 if (ecx & (1 << 20))
734                         sse_opts |= 1 << SIMD_VERSION_SSE42;
735         }
736
737         /* Yes, all this needs to be done to check for sse4a.
738            See: "Amd: CPUID Specification"
739          */
740         if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
741                 /* eax greater or equal than 0x80000001, ebx = 'htuA', ecx = DMAc', edx = 'itne'*/
742                 if ((((unsigned int) eax) >= 0x80000001) && (ebx == 0x68747541) && (ecx == 0x444D4163) && (edx == 0x69746E65)) {
743                         cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
744                         if (ecx & (1 << 6))
745                                 sse_opts |= 1 << SIMD_VERSION_SSE4a;
746                 }
747         }
748
749
750         return sse_opts;        
751 }
752
753 /*
754  * Determine whenever the trap whose info is in SIGINFO is caused by
755  * integer overflow.
756  */
757 gboolean
758 mono_arch_is_int_overflow (void *sigctx, void *info)
759 {
760         MonoContext ctx;
761         guint8* ip;
762
763         mono_arch_sigctx_to_monoctx (sigctx, &ctx);
764
765         ip = (guint8*)ctx.eip;
766
767         if ((ip [0] == 0xf7) && (x86_modrm_mod (ip [1]) == 0x3) && (x86_modrm_reg (ip [1]) == 0x7)) {
768                 gint32 reg;
769
770                 /* idiv REG */
771                 switch (x86_modrm_rm (ip [1])) {
772                 case X86_EAX:
773                         reg = ctx.eax;
774                         break;
775                 case X86_ECX:
776                         reg = ctx.ecx;
777                         break;
778                 case X86_EDX:
779                         reg = ctx.edx;
780                         break;
781                 case X86_EBX:
782                         reg = ctx.ebx;
783                         break;
784                 case X86_ESI:
785                         reg = ctx.esi;
786                         break;
787                 case X86_EDI:
788                         reg = ctx.edi;
789                         break;
790                 default:
791                         g_assert_not_reached ();
792                         reg = -1;
793                 }
794
795                 if (reg == -1)
796                         return TRUE;
797         }
798                         
799         return FALSE;
800 }
801
802 GList *
803 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
804 {
805         GList *vars = NULL;
806         int i;
807
808         for (i = 0; i < cfg->num_varinfo; i++) {
809                 MonoInst *ins = cfg->varinfo [i];
810                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
811
812                 /* unused vars */
813                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
814                         continue;
815
816                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
817                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
818                         continue;
819
820                 /* we dont allocate I1 to registers because there is no simply way to sign extend 
821                  * 8bit quantities in caller saved registers on x86 */
822                 if (mono_is_regsize_var (ins->inst_vtype) && (ins->inst_vtype->type != MONO_TYPE_I1)) {
823                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
824                         g_assert (i == vmv->idx);
825                         vars = g_list_prepend (vars, vmv);
826                 }
827         }
828
829         vars = mono_varlist_sort (cfg, vars, 0);
830
831         return vars;
832 }
833
834 GList *
835 mono_arch_get_global_int_regs (MonoCompile *cfg)
836 {
837         GList *regs = NULL;
838
839         /* we can use 3 registers for global allocation */
840         regs = g_list_prepend (regs, (gpointer)X86_EBX);
841         regs = g_list_prepend (regs, (gpointer)X86_ESI);
842         regs = g_list_prepend (regs, (gpointer)X86_EDI);
843
844         return regs;
845 }
846
847 /*
848  * mono_arch_regalloc_cost:
849  *
850  *  Return the cost, in number of memory references, of the action of 
851  * allocating the variable VMV into a register during global register
852  * allocation.
853  */
854 guint32
855 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
856 {
857         MonoInst *ins = cfg->varinfo [vmv->idx];
858
859         if (cfg->method->save_lmf)
860                 /* The register is already saved */
861                 return (ins->opcode == OP_ARG) ? 1 : 0;
862         else
863                 /* push+pop+possible load if it is an argument */
864                 return (ins->opcode == OP_ARG) ? 3 : 2;
865 }
866
867 static void
868 set_needs_stack_frame (MonoCompile *cfg, gboolean flag)
869 {
870         static int inited = FALSE;
871         static int count = 0;
872
873         if (cfg->arch.need_stack_frame_inited) {
874                 g_assert (cfg->arch.need_stack_frame == flag);
875                 return;
876         }
877
878         cfg->arch.need_stack_frame = flag;
879         cfg->arch.need_stack_frame_inited = TRUE;
880
881         if (flag)
882                 return;
883
884         if (!inited) {
885                 mono_counters_register ("Could eliminate stack frame", MONO_COUNTER_INT|MONO_COUNTER_JIT, &count);
886                 inited = TRUE;
887         }
888         ++count;
889
890         //g_print ("will eliminate %s.%s.%s\n", cfg->method->klass->name_space, cfg->method->klass->name, cfg->method->name);
891 }
892
893 static gboolean
894 needs_stack_frame (MonoCompile *cfg)
895 {
896         MonoMethodSignature *sig;
897         MonoMethodHeader *header;
898         gboolean result = FALSE;
899
900 #if defined(__APPLE__)
901         /*OSX requires stack frame code to have the correct alignment. */
902         return TRUE;
903 #endif
904
905         if (cfg->arch.need_stack_frame_inited)
906                 return cfg->arch.need_stack_frame;
907
908         header = mono_method_get_header (cfg->method);
909         sig = mono_method_signature (cfg->method);
910
911         if (cfg->disable_omit_fp)
912                 result = TRUE;
913         else if (cfg->flags & MONO_CFG_HAS_ALLOCA)
914                 result = TRUE;
915         else if (cfg->method->save_lmf)
916                 result = TRUE;
917         else if (cfg->stack_offset)
918                 result = TRUE;
919         else if (cfg->param_area)
920                 result = TRUE;
921         else if (cfg->flags & (MONO_CFG_HAS_CALLS | MONO_CFG_HAS_ALLOCA | MONO_CFG_HAS_TAIL))
922                 result = TRUE;
923         else if (header->num_clauses)
924                 result = TRUE;
925         else if (sig->param_count + sig->hasthis)
926                 result = TRUE;
927         else if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
928                 result = TRUE;
929         else if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
930                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
931                 result = TRUE;
932
933         set_needs_stack_frame (cfg, result);
934
935         return cfg->arch.need_stack_frame;
936 }
937
938 /*
939  * Set var information according to the calling convention. X86 version.
940  * The locals var stuff should most likely be split in another method.
941  */
942 void
943 mono_arch_allocate_vars (MonoCompile *cfg)
944 {
945         MonoMethodSignature *sig;
946         MonoMethodHeader *header;
947         MonoInst *inst;
948         guint32 locals_stack_size, locals_stack_align;
949         int i, offset;
950         gint32 *offsets;
951         CallInfo *cinfo;
952
953         header = mono_method_get_header (cfg->method);
954         sig = mono_method_signature (cfg->method);
955
956         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
957
958         cfg->frame_reg = X86_EBP;
959         offset = 0;
960
961         /* Reserve space to save LMF and caller saved registers */
962
963         if (cfg->method->save_lmf) {
964                 offset += sizeof (MonoLMF);
965         } else {
966                 if (cfg->used_int_regs & (1 << X86_EBX)) {
967                         offset += 4;
968                 }
969
970                 if (cfg->used_int_regs & (1 << X86_EDI)) {
971                         offset += 4;
972                 }
973
974                 if (cfg->used_int_regs & (1 << X86_ESI)) {
975                         offset += 4;
976                 }
977         }
978
979         switch (cinfo->ret.storage) {
980         case ArgValuetypeInReg:
981                 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
982                 offset += 8;
983                 cfg->ret->opcode = OP_REGOFFSET;
984                 cfg->ret->inst_basereg = X86_EBP;
985                 cfg->ret->inst_offset = - offset;
986                 break;
987         default:
988                 break;
989         }
990
991         /* Allocate locals */
992         offsets = mono_allocate_stack_slots (cfg, &locals_stack_size, &locals_stack_align);
993         if (locals_stack_align) {
994                 offset += (locals_stack_align - 1);
995                 offset &= ~(locals_stack_align - 1);
996         }
997         /*
998          * EBP is at alignment 8 % MONO_ARCH_FRAME_ALIGNMENT, so if we
999          * have locals larger than 8 bytes we need to make sure that
1000          * they have the appropriate offset.
1001          */
1002         if (MONO_ARCH_FRAME_ALIGNMENT > 8 && locals_stack_align > 8)
1003                 offset += MONO_ARCH_FRAME_ALIGNMENT - sizeof (gpointer) * 2;
1004         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1005                 if (offsets [i] != -1) {
1006                         MonoInst *inst = cfg->varinfo [i];
1007                         inst->opcode = OP_REGOFFSET;
1008                         inst->inst_basereg = X86_EBP;
1009                         inst->inst_offset = - (offset + offsets [i]);
1010                         //printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
1011                 }
1012         }
1013         offset += locals_stack_size;
1014
1015
1016         /*
1017          * Allocate arguments+return value
1018          */
1019
1020         switch (cinfo->ret.storage) {
1021         case ArgOnStack:
1022                 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1023                         /* 
1024                          * In the new IR, the cfg->vret_addr variable represents the
1025                          * vtype return value.
1026                          */
1027                         cfg->vret_addr->opcode = OP_REGOFFSET;
1028                         cfg->vret_addr->inst_basereg = cfg->frame_reg;
1029                         cfg->vret_addr->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
1030                         if (G_UNLIKELY (cfg->verbose_level > 1)) {
1031                                 printf ("vret_addr =");
1032                                 mono_print_ins (cfg->vret_addr);
1033                         }
1034                 } else {
1035                         cfg->ret->opcode = OP_REGOFFSET;
1036                         cfg->ret->inst_basereg = X86_EBP;
1037                         cfg->ret->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
1038                 }
1039                 break;
1040         case ArgValuetypeInReg:
1041                 break;
1042         case ArgInIReg:
1043                 cfg->ret->opcode = OP_REGVAR;
1044                 cfg->ret->inst_c0 = cinfo->ret.reg;
1045                 cfg->ret->dreg = cinfo->ret.reg;
1046                 break;
1047         case ArgNone:
1048         case ArgOnFloatFpStack:
1049         case ArgOnDoubleFpStack:
1050                 break;
1051         default:
1052                 g_assert_not_reached ();
1053         }
1054
1055         if (sig->call_convention == MONO_CALL_VARARG) {
1056                 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1057                 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
1058         }
1059
1060         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1061                 ArgInfo *ainfo = &cinfo->args [i];
1062                 inst = cfg->args [i];
1063                 if (inst->opcode != OP_REGVAR) {
1064                         inst->opcode = OP_REGOFFSET;
1065                         inst->inst_basereg = X86_EBP;
1066                 }
1067                 inst->inst_offset = ainfo->offset + ARGS_OFFSET;
1068         }
1069
1070         cfg->stack_offset = offset;
1071 }
1072
1073 void
1074 mono_arch_create_vars (MonoCompile *cfg)
1075 {
1076         MonoMethodSignature *sig;
1077         CallInfo *cinfo;
1078
1079         sig = mono_method_signature (cfg->method);
1080
1081         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
1082
1083         if (cinfo->ret.storage == ArgValuetypeInReg)
1084                 cfg->ret_var_is_local = TRUE;
1085         if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig->ret)) {
1086                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1087         }
1088 }
1089
1090 /*
1091  * It is expensive to adjust esp for each individual fp argument pushed on the stack
1092  * so we try to do it just once when we have multiple fp arguments in a row.
1093  * We don't use this mechanism generally because for int arguments the generated code
1094  * is slightly bigger and new generation cpus optimize away the dependency chains
1095  * created by push instructions on the esp value.
1096  * fp_arg_setup is the first argument in the execution sequence where the esp register
1097  * is modified.
1098  */
1099 static G_GNUC_UNUSED int
1100 collect_fp_stack_space (MonoMethodSignature *sig, int start_arg, int *fp_arg_setup)
1101 {
1102         int fp_space = 0;
1103         MonoType *t;
1104
1105         for (; start_arg < sig->param_count; ++start_arg) {
1106                 t = mini_type_get_underlying_type (NULL, sig->params [start_arg]);
1107                 if (!t->byref && t->type == MONO_TYPE_R8) {
1108                         fp_space += sizeof (double);
1109                         *fp_arg_setup = start_arg;
1110                 } else {
1111                         break;
1112                 }
1113         }
1114         return fp_space;
1115 }
1116
1117 static void
1118 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1119 {
1120         MonoMethodSignature *tmp_sig;
1121
1122         /* FIXME: Add support for signature tokens to AOT */
1123         cfg->disable_aot = TRUE;
1124
1125         /*
1126          * mono_ArgIterator_Setup assumes the signature cookie is 
1127          * passed first and all the arguments which were before it are
1128          * passed on the stack after the signature. So compensate by 
1129          * passing a different signature.
1130          */
1131         tmp_sig = mono_metadata_signature_dup (call->signature);
1132         tmp_sig->param_count -= call->signature->sentinelpos;
1133         tmp_sig->sentinelpos = 0;
1134         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1135
1136         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig);
1137 }
1138
1139 #ifdef ENABLE_LLVM
1140 LLVMCallInfo*
1141 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
1142 {
1143         int i, n;
1144         CallInfo *cinfo;
1145         ArgInfo *ainfo;
1146         int j;
1147         LLVMCallInfo *linfo;
1148
1149         n = sig->param_count + sig->hasthis;
1150
1151         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke);
1152
1153         linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
1154
1155         /*
1156          * LLVM always uses the native ABI while we use our own ABI, the
1157          * only difference is the handling of vtypes:
1158          * - we only pass/receive them in registers in some cases, and only 
1159          *   in 1 or 2 integer registers.
1160          */
1161         if (cinfo->ret.storage == ArgValuetypeInReg) {
1162                 if (sig->pinvoke) {
1163                         cfg->exception_message = g_strdup ("pinvoke + vtypes");
1164                         cfg->disable_llvm = TRUE;
1165                         return linfo;
1166                 }
1167
1168                 cfg->exception_message = g_strdup ("vtype ret in call");
1169                 cfg->disable_llvm = TRUE;
1170                 /*
1171                 linfo->ret.storage = LLVMArgVtypeInReg;
1172                 for (j = 0; j < 2; ++j)
1173                         linfo->ret.pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, cinfo->ret.pair_storage [j]);
1174                 */
1175         }
1176
1177         if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage == ArgInIReg) {
1178                 /* Vtype returned using a hidden argument */
1179                 linfo->ret.storage = LLVMArgVtypeRetAddr;
1180         }
1181
1182         if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != ArgInIReg) {
1183                 // FIXME:
1184                 cfg->exception_message = g_strdup ("vtype ret in call");
1185                 cfg->disable_llvm = TRUE;
1186         }
1187
1188         for (i = 0; i < n; ++i) {
1189                 ainfo = cinfo->args + i;
1190
1191                 linfo->args [i].storage = LLVMArgNone;
1192
1193                 switch (ainfo->storage) {
1194                 case ArgInIReg:
1195                         linfo->args [i].storage = LLVMArgInIReg;
1196                         break;
1197                 case ArgInDoubleSSEReg:
1198                 case ArgInFloatSSEReg:
1199                         linfo->args [i].storage = LLVMArgInFPReg;
1200                         break;
1201                 case ArgOnStack:
1202                         if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
1203                                 linfo->args [i].storage = LLVMArgVtypeByVal;
1204                         } else {
1205                                 linfo->args [i].storage = LLVMArgInIReg;
1206                                 if (!sig->params [i - sig->hasthis]->byref) {
1207                                         if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4) {
1208                                                 linfo->args [i].storage = LLVMArgInFPReg;
1209                                         } else if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8) {
1210                                                 linfo->args [i].storage = LLVMArgInFPReg;
1211                                         }
1212                                 }
1213                         }
1214                         break;
1215                 case ArgValuetypeInReg:
1216                         if (sig->pinvoke) {
1217                                 cfg->exception_message = g_strdup ("pinvoke + vtypes");
1218                                 cfg->disable_llvm = TRUE;
1219                                 return linfo;
1220                         }
1221
1222                         cfg->exception_message = g_strdup ("vtype arg");
1223                         cfg->disable_llvm = TRUE;
1224                         /*
1225                         linfo->args [i].storage = LLVMArgVtypeInReg;
1226                         for (j = 0; j < 2; ++j)
1227                                 linfo->args [i].pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, ainfo->pair_storage [j]);
1228                         */
1229                         break;
1230                 default:
1231                         cfg->exception_message = g_strdup ("ainfo->storage");
1232                         cfg->disable_llvm = TRUE;
1233                         break;
1234                 }
1235         }
1236
1237         return linfo;
1238 }
1239 #endif
1240
1241 void
1242 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1243 {
1244         MonoInst *arg, *in;
1245         MonoMethodSignature *sig;
1246         int i, n;
1247         CallInfo *cinfo;
1248         int sentinelpos = 0;
1249
1250         sig = call->signature;
1251         n = sig->param_count + sig->hasthis;
1252
1253         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
1254
1255         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1256                 sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0);
1257
1258         if (cinfo->need_stack_align) {
1259                 MONO_INST_NEW (cfg, arg, OP_SUB_IMM);
1260                 arg->dreg = X86_ESP;
1261                 arg->sreg1 = X86_ESP;
1262                 arg->inst_imm = cinfo->stack_align_amount;
1263                 MONO_ADD_INS (cfg->cbb, arg);
1264         }
1265
1266         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1267                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1268                         /*
1269                          * Tell the JIT to use a more efficient calling convention: call using
1270                          * OP_CALL, compute the result location after the call, and save the 
1271                          * result there.
1272                          */
1273                         call->vret_in_reg = TRUE;
1274                         if (call->vret_var)
1275                                 NULLIFY_INS (call->vret_var);
1276                 }
1277         }
1278
1279         /* Handle the case where there are no implicit arguments */
1280         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) {
1281                 emit_sig_cookie (cfg, call, cinfo);
1282         }
1283
1284         /* Arguments are pushed in the reverse order */
1285         for (i = n - 1; i >= 0; i --) {
1286                 ArgInfo *ainfo = cinfo->args + i;
1287                 MonoType *t;
1288
1289                 if (i >= sig->hasthis)
1290                         t = sig->params [i - sig->hasthis];
1291                 else
1292                         t = &mono_defaults.int_class->byval_arg;
1293                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1294
1295                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1296
1297                 in = call->args [i];
1298                 arg->cil_code = in->cil_code;
1299                 arg->sreg1 = in->dreg;
1300                 arg->type = in->type;
1301
1302                 g_assert (in->dreg != -1);
1303
1304                 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
1305                         guint32 align;
1306                         guint32 size;
1307
1308                         g_assert (in->klass);
1309
1310                         if (t->type == MONO_TYPE_TYPEDBYREF) {
1311                                 size = sizeof (MonoTypedRef);
1312                                 align = sizeof (gpointer);
1313                         }
1314                         else {
1315                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &align, sig->pinvoke);
1316                         }
1317
1318                         if (size > 0) {
1319                                 arg->opcode = OP_OUTARG_VT;
1320                                 arg->sreg1 = in->dreg;
1321                                 arg->klass = in->klass;
1322                                 arg->backend.size = size;
1323
1324                                 MONO_ADD_INS (cfg->cbb, arg);
1325                         }
1326                 }
1327                 else {
1328                         switch (ainfo->storage) {
1329                         case ArgOnStack:
1330                                 arg->opcode = OP_X86_PUSH;
1331                                 if (!t->byref) {
1332                                         if (t->type == MONO_TYPE_R4) {
1333                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
1334                                                 arg->opcode = OP_STORER4_MEMBASE_REG;
1335                                                 arg->inst_destbasereg = X86_ESP;
1336                                                 arg->inst_offset = 0;
1337                                         } else if (t->type == MONO_TYPE_R8) {
1338                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
1339                                                 arg->opcode = OP_STORER8_MEMBASE_REG;
1340                                                 arg->inst_destbasereg = X86_ESP;
1341                                                 arg->inst_offset = 0;
1342                                         } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) {
1343                                                 arg->sreg1 ++;
1344                                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2);
1345                                         }
1346                                 }
1347                                 break;
1348                         default:
1349                                 g_assert_not_reached ();
1350                         }
1351                         
1352                         MONO_ADD_INS (cfg->cbb, arg);
1353                 }
1354
1355                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
1356                         /* Emit the signature cookie just before the implicit arguments */
1357                         emit_sig_cookie (cfg, call, cinfo);
1358                 }
1359         }
1360
1361         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1362                 MonoInst *vtarg;
1363
1364                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1365                         /* Already done */
1366                 }
1367                 else if (cinfo->ret.storage == ArgInIReg) {
1368                         NOT_IMPLEMENTED;
1369                         /* The return address is passed in a register */
1370                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1371                         vtarg->sreg1 = call->inst.dreg;
1372                         vtarg->dreg = mono_alloc_ireg (cfg);
1373                         MONO_ADD_INS (cfg->cbb, vtarg);
1374                                 
1375                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
1376                 } else {
1377                         MonoInst *vtarg;
1378                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1379                         vtarg->type = STACK_MP;
1380                         vtarg->sreg1 = call->vret_var->dreg;
1381                         MONO_ADD_INS (cfg->cbb, vtarg);
1382                 }
1383
1384                 /* if the function returns a struct on stack, the called method already does a ret $0x4 */
1385                 if (cinfo->ret.storage != ArgValuetypeInReg)
1386                         cinfo->stack_usage -= 4;
1387         }
1388
1389         call->stack_usage = cinfo->stack_usage;
1390 }
1391
1392 void
1393 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1394 {
1395         MonoInst *arg;
1396         int size = ins->backend.size;
1397
1398         if (size <= 4) {
1399                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE);
1400                 arg->sreg1 = src->dreg;
1401
1402                 MONO_ADD_INS (cfg->cbb, arg);
1403         } else if (size <= 20) {        
1404                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 4));
1405                 mini_emit_memcpy (cfg, X86_ESP, 0, src->dreg, 0, size, 4);
1406         } else {
1407                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ);
1408                 arg->inst_basereg = src->dreg;
1409                 arg->inst_offset = 0;
1410                 arg->inst_imm = size;
1411                                         
1412                 MONO_ADD_INS (cfg->cbb, arg);
1413         }
1414 }
1415
1416 void
1417 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1418 {
1419         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1420
1421         if (!ret->byref) {
1422                 if (ret->type == MONO_TYPE_R4) {
1423                         if (COMPILE_LLVM (cfg))
1424                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1425                         /* Nothing to do */
1426                         return;
1427                 } else if (ret->type == MONO_TYPE_R8) {
1428                         if (COMPILE_LLVM (cfg))
1429                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1430                         /* Nothing to do */
1431                         return;
1432                 } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1433                         if (COMPILE_LLVM (cfg))
1434                                 MONO_EMIT_NEW_UNALU (cfg, OP_LMOVE, cfg->ret->dreg, val->dreg);
1435                         else {
1436                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EAX, val->dreg + 1);
1437                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EDX, val->dreg + 2);
1438                         }
1439                         return;
1440                 }
1441         }
1442                         
1443         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1444 }
1445
1446 /*
1447  * Allow tracing to work with this interface (with an optional argument)
1448  */
1449 void*
1450 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1451 {
1452         guchar *code = p;
1453
1454         g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
1455         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
1456
1457         /* if some args are passed in registers, we need to save them here */
1458         x86_push_reg (code, X86_EBP);
1459
1460         if (cfg->compile_aot) {
1461                 x86_push_imm (code, cfg->method);
1462                 x86_mov_reg_imm (code, X86_EAX, func);
1463                 x86_call_reg (code, X86_EAX);
1464         } else {
1465                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, cfg->method);
1466                 x86_push_imm (code, cfg->method);
1467                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1468                 x86_call_code (code, 0);
1469         }
1470         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT);
1471
1472         return code;
1473 }
1474
1475 enum {
1476         SAVE_NONE,
1477         SAVE_STRUCT,
1478         SAVE_EAX,
1479         SAVE_EAX_EDX,
1480         SAVE_FP
1481 };
1482
1483 void*
1484 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1485 {
1486         guchar *code = p;
1487         int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE;
1488         MonoMethod *method = cfg->method;
1489         
1490         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type) {
1491         case MONO_TYPE_VOID:
1492                 /* special case string .ctor icall */
1493                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class) {
1494                         save_mode = SAVE_EAX;
1495                         stack_usage = enable_arguments ? 8 : 4;
1496                 } else
1497                         save_mode = SAVE_NONE;
1498                 break;
1499         case MONO_TYPE_I8:
1500         case MONO_TYPE_U8:
1501                 save_mode = SAVE_EAX_EDX;
1502                 stack_usage = enable_arguments ? 16 : 8;
1503                 break;
1504         case MONO_TYPE_R4:
1505         case MONO_TYPE_R8:
1506                 save_mode = SAVE_FP;
1507                 stack_usage = enable_arguments ? 16 : 8;
1508                 break;
1509         case MONO_TYPE_GENERICINST:
1510                 if (!mono_type_generic_inst_is_valuetype (mono_method_signature (method)->ret)) {
1511                         save_mode = SAVE_EAX;
1512                         stack_usage = enable_arguments ? 8 : 4;
1513                         break;
1514                 }
1515                 /* Fall through */
1516         case MONO_TYPE_VALUETYPE:
1517                 // FIXME: Handle SMALL_STRUCT_IN_REG here for proper alignment on darwin-x86
1518                 save_mode = SAVE_STRUCT;
1519                 stack_usage = enable_arguments ? 4 : 0;
1520                 break;
1521         default:
1522                 save_mode = SAVE_EAX;
1523                 stack_usage = enable_arguments ? 8 : 4;
1524                 break;
1525         }
1526
1527         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage - 4);
1528
1529         switch (save_mode) {
1530         case SAVE_EAX_EDX:
1531                 x86_push_reg (code, X86_EDX);
1532                 x86_push_reg (code, X86_EAX);
1533                 if (enable_arguments) {
1534                         x86_push_reg (code, X86_EDX);
1535                         x86_push_reg (code, X86_EAX);
1536                         arg_size = 8;
1537                 }
1538                 break;
1539         case SAVE_EAX:
1540                 x86_push_reg (code, X86_EAX);
1541                 if (enable_arguments) {
1542                         x86_push_reg (code, X86_EAX);
1543                         arg_size = 4;
1544                 }
1545                 break;
1546         case SAVE_FP:
1547                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1548                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1549                 if (enable_arguments) {
1550                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1551                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1552                         arg_size = 8;
1553                 }
1554                 break;
1555         case SAVE_STRUCT:
1556                 if (enable_arguments) {
1557                         x86_push_membase (code, X86_EBP, 8);
1558                         arg_size = 4;
1559                 }
1560                 break;
1561         case SAVE_NONE:
1562         default:
1563                 break;
1564         }
1565
1566         if (cfg->compile_aot) {
1567                 x86_push_imm (code, method);
1568                 x86_mov_reg_imm (code, X86_EAX, func);
1569                 x86_call_reg (code, X86_EAX);
1570         } else {
1571                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
1572                 x86_push_imm (code, method);
1573                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1574                 x86_call_code (code, 0);
1575         }
1576
1577         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1578
1579         switch (save_mode) {
1580         case SAVE_EAX_EDX:
1581                 x86_pop_reg (code, X86_EAX);
1582                 x86_pop_reg (code, X86_EDX);
1583                 break;
1584         case SAVE_EAX:
1585                 x86_pop_reg (code, X86_EAX);
1586                 break;
1587         case SAVE_FP:
1588                 x86_fld_membase (code, X86_ESP, 0, TRUE);
1589                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1590                 break;
1591         case SAVE_NONE:
1592         default:
1593                 break;
1594         }
1595         
1596         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage);
1597
1598         return code;
1599 }
1600
1601 #define EMIT_COND_BRANCH(ins,cond,sign) \
1602 if (ins->inst_true_bb->native_offset) { \
1603         x86_branch (code, cond, cfg->native_code + ins->inst_true_bb->native_offset, sign); \
1604 } else { \
1605         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1606         if ((cfg->opt & MONO_OPT_BRANCH) && \
1607             x86_is_imm8 (ins->inst_true_bb->max_offset - cpos)) \
1608                 x86_branch8 (code, cond, 0, sign); \
1609         else \
1610                 x86_branch32 (code, cond, 0, sign); \
1611 }
1612
1613 /*  
1614  *      Emit an exception if condition is fail and
1615  *  if possible do a directly branch to target 
1616  */
1617 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
1618         do {                                                        \
1619                 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1620                 if (tins == NULL) {                                                                             \
1621                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1622                                         MONO_PATCH_INFO_EXC, exc_name);  \
1623                         x86_branch32 (code, cond, 0, signed);               \
1624                 } else {        \
1625                         EMIT_COND_BRANCH (tins, cond, signed);  \
1626                 }                       \
1627         } while (0); 
1628
1629 #define EMIT_FPCOMPARE(code) do { \
1630         x86_fcompp (code); \
1631         x86_fnstsw (code); \
1632 } while (0); 
1633
1634
1635 static guint8*
1636 emit_call (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data)
1637 {
1638         mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
1639         x86_call_code (code, 0);
1640
1641         return code;
1642 }
1643
1644 #define INST_IGNORES_CFLAGS(opcode) (!(((opcode) == OP_ADC) || ((opcode) == OP_IADC) || ((opcode) == OP_ADC_IMM) || ((opcode) == OP_IADC_IMM) || ((opcode) == OP_SBB) || ((opcode) == OP_ISBB) || ((opcode) == OP_SBB_IMM) || ((opcode) == OP_ISBB_IMM)))
1645
1646 /*
1647  * mono_peephole_pass_1:
1648  *
1649  *   Perform peephole opts which should/can be performed before local regalloc
1650  */
1651 void
1652 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1653 {
1654         MonoInst *ins, *n;
1655
1656         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1657                 MonoInst *last_ins = ins->prev;
1658
1659                 switch (ins->opcode) {
1660                 case OP_IADD_IMM:
1661                 case OP_ADD_IMM:
1662                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
1663                                 /* 
1664                                  * X86_LEA is like ADD, but doesn't have the
1665                                  * sreg1==dreg restriction.
1666                                  */
1667                                 ins->opcode = OP_X86_LEA_MEMBASE;
1668                                 ins->inst_basereg = ins->sreg1;
1669                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1670                                 ins->opcode = OP_X86_INC_REG;
1671                         break;
1672                 case OP_SUB_IMM:
1673                 case OP_ISUB_IMM:
1674                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
1675                                 ins->opcode = OP_X86_LEA_MEMBASE;
1676                                 ins->inst_basereg = ins->sreg1;
1677                                 ins->inst_imm = -ins->inst_imm;
1678                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1679                                 ins->opcode = OP_X86_DEC_REG;
1680                         break;
1681                 case OP_COMPARE_IMM:
1682                 case OP_ICOMPARE_IMM:
1683                         /* OP_COMPARE_IMM (reg, 0) 
1684                          * --> 
1685                          * OP_X86_TEST_NULL (reg) 
1686                          */
1687                         if (!ins->inst_imm)
1688                                 ins->opcode = OP_X86_TEST_NULL;
1689                         break;
1690                 case OP_X86_COMPARE_MEMBASE_IMM:
1691                         /* 
1692                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
1693                          * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm
1694                          * -->
1695                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
1696                          * OP_COMPARE_IMM reg, imm
1697                          *
1698                          * Note: if imm = 0 then OP_COMPARE_IMM replaced with OP_X86_TEST_NULL
1699                          */
1700                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
1701                             ins->inst_basereg == last_ins->inst_destbasereg &&
1702                             ins->inst_offset == last_ins->inst_offset) {
1703                                         ins->opcode = OP_COMPARE_IMM;
1704                                         ins->sreg1 = last_ins->sreg1;
1705
1706                                         /* check if we can remove cmp reg,0 with test null */
1707                                         if (!ins->inst_imm)
1708                                                 ins->opcode = OP_X86_TEST_NULL;
1709                                 }
1710
1711                         break;                  
1712                 case OP_X86_PUSH_MEMBASE:
1713                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG ||
1714                                          last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1715                             ins->inst_basereg == last_ins->inst_destbasereg &&
1716                             ins->inst_offset == last_ins->inst_offset) {
1717                                     ins->opcode = OP_X86_PUSH;
1718                                     ins->sreg1 = last_ins->sreg1;
1719                         }
1720                         break;
1721                 }
1722
1723                 mono_peephole_ins (bb, ins);
1724         }
1725 }
1726
1727 void
1728 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1729 {
1730         MonoInst *ins, *n;
1731
1732         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1733                 switch (ins->opcode) {
1734                 case OP_ICONST:
1735                         /* reg = 0 -> XOR (reg, reg) */
1736                         /* XOR sets cflags on x86, so we cant do it always */
1737                         if (ins->inst_c0 == 0 && (!ins->next || (ins->next && INST_IGNORES_CFLAGS (ins->next->opcode)))) {
1738                                 MonoInst *ins2;
1739
1740                                 ins->opcode = OP_IXOR;
1741                                 ins->sreg1 = ins->dreg;
1742                                 ins->sreg2 = ins->dreg;
1743
1744                                 /* 
1745                                  * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG 
1746                                  * since it takes 3 bytes instead of 7.
1747                                  */
1748                                 for (ins2 = ins->next; ins2; ins2 = ins2->next) {
1749                                         if ((ins2->opcode == OP_STORE_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
1750                                                 ins2->opcode = OP_STORE_MEMBASE_REG;
1751                                                 ins2->sreg1 = ins->dreg;
1752                                         }
1753                                         else if ((ins2->opcode == OP_STOREI4_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
1754                                                 ins2->opcode = OP_STOREI4_MEMBASE_REG;
1755                                                 ins2->sreg1 = ins->dreg;
1756                                         }
1757                                         else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM)) {
1758                                                 /* Continue iteration */
1759                                         }
1760                                         else
1761                                                 break;
1762                                 }
1763                         }
1764                         break;
1765                 case OP_IADD_IMM:
1766                 case OP_ADD_IMM:
1767                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1768                                 ins->opcode = OP_X86_INC_REG;
1769                         break;
1770                 case OP_ISUB_IMM:
1771                 case OP_SUB_IMM:
1772                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1773                                 ins->opcode = OP_X86_DEC_REG;
1774                         break;
1775                 }
1776
1777                 mono_peephole_ins (bb, ins);
1778         }
1779 }
1780
1781 /*
1782  * mono_arch_lowering_pass:
1783  *
1784  *  Converts complex opcodes into simpler ones so that each IR instruction
1785  * corresponds to one machine instruction.
1786  */
1787 void
1788 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1789 {
1790         MonoInst *ins, *next;
1791
1792         /*
1793          * FIXME: Need to add more instructions, but the current machine 
1794          * description can't model some parts of the composite instructions like
1795          * cdq.
1796          */
1797         MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
1798                 switch (ins->opcode) {
1799                 case OP_IREM_IMM:
1800                 case OP_IDIV_IMM:
1801                 case OP_IDIV_UN_IMM:
1802                 case OP_IREM_UN_IMM:
1803                         /* 
1804                          * Keep the cases where we could generated optimized code, otherwise convert
1805                          * to the non-imm variant.
1806                          */
1807                         if ((ins->opcode == OP_IREM_IMM) && mono_is_power_of_two (ins->inst_imm) >= 0)
1808                                 break;
1809                         mono_decompose_op_imm (cfg, bb, ins);
1810                         break;
1811                 default:
1812                         break;
1813                 }
1814         }
1815
1816         bb->max_vreg = cfg->next_vreg;
1817 }
1818
1819 static const int 
1820 branch_cc_table [] = {
1821         X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
1822         X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
1823         X86_CC_O, X86_CC_NO, X86_CC_C, X86_CC_NC
1824 };
1825
1826 /* Maps CMP_... constants to X86_CC_... constants */
1827 static const int
1828 cc_table [] = {
1829         X86_CC_EQ, X86_CC_NE, X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT,
1830         X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT
1831 };
1832
1833 static const int
1834 cc_signed_table [] = {
1835         TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
1836         FALSE, FALSE, FALSE, FALSE
1837 };
1838
1839 static unsigned char*
1840 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
1841 {
1842 #define XMM_TEMP_REG 0
1843         /*This SSE2 optimization must not be done which OPT_SIMD in place as it clobbers xmm0.*/
1844         /*The xmm pass decomposes OP_FCONV_ ops anyway anyway.*/
1845         if (cfg->opt & MONO_OPT_SSE2 && size < 8 && !(cfg->opt & MONO_OPT_SIMD)) {
1846                 /* optimize by assigning a local var for this use so we avoid
1847                  * the stack manipulations */
1848                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1849                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1850                 x86_movsd_reg_membase (code, XMM_TEMP_REG, X86_ESP, 0);
1851                 x86_cvttsd2si (code, dreg, XMM_TEMP_REG);
1852                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1853                 if (size == 1)
1854                         x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
1855                 else if (size == 2)
1856                         x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
1857                 return code;
1858         }
1859         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
1860         x86_fnstcw_membase(code, X86_ESP, 0);
1861         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
1862         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
1863         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
1864         x86_fldcw_membase (code, X86_ESP, 2);
1865         if (size == 8) {
1866                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1867                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
1868                 x86_pop_reg (code, dreg);
1869                 /* FIXME: need the high register 
1870                  * x86_pop_reg (code, dreg_high);
1871                  */
1872         } else {
1873                 x86_push_reg (code, X86_EAX); // SP = SP - 4
1874                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
1875                 x86_pop_reg (code, dreg);
1876         }
1877         x86_fldcw_membase (code, X86_ESP, 0);
1878         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
1879
1880         if (size == 1)
1881                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
1882         else if (size == 2)
1883                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
1884         return code;
1885 }
1886
1887 static unsigned char*
1888 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1889 {
1890         int sreg = tree->sreg1;
1891         int need_touch = FALSE;
1892
1893 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
1894         need_touch = TRUE;
1895 #endif
1896
1897         if (need_touch) {
1898                 guint8* br[5];
1899
1900                 /*
1901                  * Under Windows:
1902                  * If requested stack size is larger than one page,
1903                  * perform stack-touch operation
1904                  */
1905                 /*
1906                  * Generate stack probe code.
1907                  * Under Windows, it is necessary to allocate one page at a time,
1908                  * "touching" stack after each successful sub-allocation. This is
1909                  * because of the way stack growth is implemented - there is a
1910                  * guard page before the lowest stack page that is currently commited.
1911                  * Stack normally grows sequentially so OS traps access to the
1912                  * guard page and commits more pages when needed.
1913                  */
1914                 x86_test_reg_imm (code, sreg, ~0xFFF);
1915                 br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
1916
1917                 br[2] = code; /* loop */
1918                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
1919                 x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
1920
1921                 /* 
1922                  * By the end of the loop, sreg2 is smaller than 0x1000, so the init routine
1923                  * that follows only initializes the last part of the area.
1924                  */
1925                 /* Same as the init code below with size==0x1000 */
1926                 if (tree->flags & MONO_INST_INIT) {
1927                         x86_push_reg (code, X86_EAX);
1928                         x86_push_reg (code, X86_ECX);
1929                         x86_push_reg (code, X86_EDI);
1930                         x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2));
1931                         x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);                              
1932                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
1933                         x86_cld (code);
1934                         x86_prefix (code, X86_REP_PREFIX);
1935                         x86_stosl (code);
1936                         x86_pop_reg (code, X86_EDI);
1937                         x86_pop_reg (code, X86_ECX);
1938                         x86_pop_reg (code, X86_EAX);
1939                 }
1940
1941                 x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
1942                 x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
1943                 br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
1944                 x86_patch (br[3], br[2]);
1945                 x86_test_reg_reg (code, sreg, sreg);
1946                 br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
1947                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
1948
1949                 br[1] = code; x86_jump8 (code, 0);
1950
1951                 x86_patch (br[0], code);
1952                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
1953                 x86_patch (br[1], code);
1954                 x86_patch (br[4], code);
1955         }
1956         else
1957                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1958
1959         if (tree->flags & MONO_INST_INIT) {
1960                 int offset = 0;
1961                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1962                         x86_push_reg (code, X86_EAX);
1963                         offset += 4;
1964                 }
1965                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1966                         x86_push_reg (code, X86_ECX);
1967                         offset += 4;
1968                 }
1969                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1970                         x86_push_reg (code, X86_EDI);
1971                         offset += 4;
1972                 }
1973                 
1974                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1975                 if (sreg != X86_ECX)
1976                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1977                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1978                                 
1979                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1980                 x86_cld (code);
1981                 x86_prefix (code, X86_REP_PREFIX);
1982                 x86_stosl (code);
1983                 
1984                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1985                         x86_pop_reg (code, X86_EDI);
1986                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1987                         x86_pop_reg (code, X86_ECX);
1988                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1989                         x86_pop_reg (code, X86_EAX);
1990         }
1991         return code;
1992 }
1993
1994
1995 static guint8*
1996 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
1997 {
1998         /* Move return value to the target register */
1999         switch (ins->opcode) {
2000         case OP_CALL:
2001         case OP_CALL_REG:
2002         case OP_CALL_MEMBASE:
2003                 if (ins->dreg != X86_EAX)
2004                         x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2005                 break;
2006         default:
2007                 break;
2008         }
2009
2010         return code;
2011 }
2012
2013 /*
2014  * mono_x86_emit_tls_get:
2015  * @code: buffer to store code to
2016  * @dreg: hard register where to place the result
2017  * @tls_offset: offset info
2018  *
2019  * mono_x86_emit_tls_get emits in @code the native code that puts in
2020  * the dreg register the item in the thread local storage identified
2021  * by tls_offset.
2022  *
2023  * Returns: a pointer to the end of the stored code
2024  */
2025 guint8*
2026 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset)
2027 {
2028 #ifdef PLATFORM_WIN32
2029         /* 
2030          * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
2031          * Journal and/or a disassembly of the TlsGet () function.
2032          */
2033         g_assert (tls_offset < 64);
2034         x86_prefix (code, X86_FS_PREFIX);
2035         x86_mov_reg_mem (code, dreg, 0x18, 4);
2036         /* Dunno what this does but TlsGetValue () contains it */
2037         x86_alu_membase_imm (code, X86_AND, dreg, 0x34, 0);
2038         x86_mov_reg_membase (code, dreg, dreg, 3600 + (tls_offset * 4), 4);
2039 #else
2040         if (optimize_for_xen) {
2041                 x86_prefix (code, X86_GS_PREFIX);
2042                 x86_mov_reg_mem (code, dreg, 0, 4);
2043                 x86_mov_reg_membase (code, dreg, dreg, tls_offset, 4);
2044         } else {
2045                 x86_prefix (code, X86_GS_PREFIX);
2046                 x86_mov_reg_mem (code, dreg, tls_offset, 4);
2047         }
2048 #endif
2049         return code;
2050 }
2051
2052 /*
2053  * emit_load_volatile_arguments:
2054  *
2055  *  Load volatile arguments from the stack to the original input registers.
2056  * Required before a tail call.
2057  */
2058 static guint8*
2059 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2060 {
2061         MonoMethod *method = cfg->method;
2062         MonoMethodSignature *sig;
2063         MonoInst *inst;
2064         CallInfo *cinfo;
2065         guint32 i;
2066
2067         /* FIXME: Generate intermediate code instead */
2068
2069         sig = mono_method_signature (method);
2070
2071         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
2072         
2073         /* This is the opposite of the code in emit_prolog */
2074
2075         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2076                 ArgInfo *ainfo = cinfo->args + i;
2077                 MonoType *arg_type;
2078                 inst = cfg->args [i];
2079
2080                 if (sig->hasthis && (i == 0))
2081                         arg_type = &mono_defaults.object_class->byval_arg;
2082                 else
2083                         arg_type = sig->params [i - sig->hasthis];
2084
2085                 /*
2086                  * On x86, the arguments are either in their original stack locations, or in
2087                  * global regs.
2088                  */
2089                 if (inst->opcode == OP_REGVAR) {
2090                         g_assert (ainfo->storage == ArgOnStack);
2091                         
2092                         x86_mov_membase_reg (code, X86_EBP, inst->inst_offset, inst->dreg, 4);
2093                 }
2094         }
2095
2096         return code;
2097 }
2098
2099 #define REAL_PRINT_REG(text,reg) \
2100 mono_assert (reg >= 0); \
2101 x86_push_reg (code, X86_EAX); \
2102 x86_push_reg (code, X86_EDX); \
2103 x86_push_reg (code, X86_ECX); \
2104 x86_push_reg (code, reg); \
2105 x86_push_imm (code, reg); \
2106 x86_push_imm (code, text " %d %p\n"); \
2107 x86_mov_reg_imm (code, X86_EAX, printf); \
2108 x86_call_reg (code, X86_EAX); \
2109 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2110 x86_pop_reg (code, X86_ECX); \
2111 x86_pop_reg (code, X86_EDX); \
2112 x86_pop_reg (code, X86_EAX);
2113
2114 /* benchmark and set based on cpu */
2115 #define LOOP_ALIGNMENT 8
2116 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2117
2118 #ifndef DISABLE_JIT
2119
2120 void
2121 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2122 {
2123         MonoInst *ins;
2124         MonoCallInst *call;
2125         guint offset;
2126         guint8 *code = cfg->native_code + cfg->code_len;
2127         int max_len, cpos;
2128
2129         if (cfg->opt & MONO_OPT_LOOP) {
2130                 int pad, align = LOOP_ALIGNMENT;
2131                 /* set alignment depending on cpu */
2132                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2133                         pad = align - pad;
2134                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2135                         x86_padding (code, pad);
2136                         cfg->code_len += pad;
2137                         bb->native_offset = cfg->code_len;
2138                 }
2139         }
2140
2141         if (cfg->verbose_level > 2)
2142                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2143
2144         cpos = bb->max_offset;
2145
2146         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2147                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2148                 g_assert (!cfg->compile_aot);
2149                 cpos += 6;
2150
2151                 cov->data [bb->dfn].cil_code = bb->cil_code;
2152                 /* this is not thread save, but good enough */
2153                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2154         }
2155
2156         offset = code - cfg->native_code;
2157
2158         mono_debug_open_block (cfg, bb, offset);
2159
2160         MONO_BB_FOR_EACH_INS (bb, ins) {
2161                 offset = code - cfg->native_code;
2162
2163                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2164
2165                 if (G_UNLIKELY (offset > (cfg->code_size - max_len - 16))) {
2166                         cfg->code_size *= 2;
2167                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2168                         code = cfg->native_code + offset;
2169                         mono_jit_stats.code_reallocs++;
2170                 }
2171
2172                 if (cfg->debug_info)
2173                         mono_debug_record_line_number (cfg, ins, offset);
2174
2175                 switch (ins->opcode) {
2176                 case OP_BIGMUL:
2177                         x86_mul_reg (code, ins->sreg2, TRUE);
2178                         break;
2179                 case OP_BIGMUL_UN:
2180                         x86_mul_reg (code, ins->sreg2, FALSE);
2181                         break;
2182                 case OP_X86_SETEQ_MEMBASE:
2183                 case OP_X86_SETNE_MEMBASE:
2184                         x86_set_membase (code, ins->opcode == OP_X86_SETEQ_MEMBASE ? X86_CC_EQ : X86_CC_NE,
2185                                          ins->inst_basereg, ins->inst_offset, TRUE);
2186                         break;
2187                 case OP_STOREI1_MEMBASE_IMM:
2188                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2189                         break;
2190                 case OP_STOREI2_MEMBASE_IMM:
2191                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2192                         break;
2193                 case OP_STORE_MEMBASE_IMM:
2194                 case OP_STOREI4_MEMBASE_IMM:
2195                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2196                         break;
2197                 case OP_STOREI1_MEMBASE_REG:
2198                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2199                         break;
2200                 case OP_STOREI2_MEMBASE_REG:
2201                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2202                         break;
2203                 case OP_STORE_MEMBASE_REG:
2204                 case OP_STOREI4_MEMBASE_REG:
2205                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2206                         break;
2207                 case OP_STORE_MEM_IMM:
2208                         x86_mov_mem_imm (code, ins->inst_p0, ins->inst_c0, 4);
2209                         break;
2210                 case OP_LOADU4_MEM:
2211                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2212                         break;
2213                 case OP_LOAD_MEM:
2214                 case OP_LOADI4_MEM:
2215                         /* These are created by the cprop pass so they use inst_imm as the source */
2216                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2217                         break;
2218                 case OP_LOADU1_MEM:
2219                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, FALSE);
2220                         break;
2221                 case OP_LOADU2_MEM:
2222                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, TRUE);
2223                         break;
2224                 case OP_LOAD_MEMBASE:
2225                 case OP_LOADI4_MEMBASE:
2226                 case OP_LOADU4_MEMBASE:
2227                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2228                         break;
2229                 case OP_LOADU1_MEMBASE:
2230                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2231                         break;
2232                 case OP_LOADI1_MEMBASE:
2233                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2234                         break;
2235                 case OP_LOADU2_MEMBASE:
2236                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2237                         break;
2238                 case OP_LOADI2_MEMBASE:
2239                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2240                         break;
2241                 case OP_ICONV_TO_I1:
2242                 case OP_SEXT_I1:
2243                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2244                         break;
2245                 case OP_ICONV_TO_I2:
2246                 case OP_SEXT_I2:
2247                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2248                         break;
2249                 case OP_ICONV_TO_U1:
2250                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2251                         break;
2252                 case OP_ICONV_TO_U2:
2253                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2254                         break;
2255                 case OP_COMPARE:
2256                 case OP_ICOMPARE:
2257                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2258                         break;
2259                 case OP_COMPARE_IMM:
2260                 case OP_ICOMPARE_IMM:
2261                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2262                         break;
2263                 case OP_X86_COMPARE_MEMBASE_REG:
2264                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2265                         break;
2266                 case OP_X86_COMPARE_MEMBASE_IMM:
2267                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2268                         break;
2269                 case OP_X86_COMPARE_MEMBASE8_IMM:
2270                         x86_alu_membase8_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2271                         break;
2272                 case OP_X86_COMPARE_REG_MEMBASE:
2273                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2274                         break;
2275                 case OP_X86_COMPARE_MEM_IMM:
2276                         x86_alu_mem_imm (code, X86_CMP, ins->inst_offset, ins->inst_imm);
2277                         break;
2278                 case OP_X86_TEST_NULL:
2279                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2280                         break;
2281                 case OP_X86_ADD_MEMBASE_IMM:
2282                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2283                         break;
2284                 case OP_X86_ADD_REG_MEMBASE:
2285                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2286                         break;
2287                 case OP_X86_SUB_MEMBASE_IMM:
2288                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2289                         break;
2290                 case OP_X86_SUB_REG_MEMBASE:
2291                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2292                         break;
2293                 case OP_X86_AND_MEMBASE_IMM:
2294                         x86_alu_membase_imm (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2295                         break;
2296                 case OP_X86_OR_MEMBASE_IMM:
2297                         x86_alu_membase_imm (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2298                         break;
2299                 case OP_X86_XOR_MEMBASE_IMM:
2300                         x86_alu_membase_imm (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2301                         break;
2302                 case OP_X86_ADD_MEMBASE_REG:
2303                         x86_alu_membase_reg (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2304                         break;
2305                 case OP_X86_SUB_MEMBASE_REG:
2306                         x86_alu_membase_reg (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2307                         break;
2308                 case OP_X86_AND_MEMBASE_REG:
2309                         x86_alu_membase_reg (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2310                         break;
2311                 case OP_X86_OR_MEMBASE_REG:
2312                         x86_alu_membase_reg (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2313                         break;
2314                 case OP_X86_XOR_MEMBASE_REG:
2315                         x86_alu_membase_reg (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2316                         break;
2317                 case OP_X86_INC_MEMBASE:
2318                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2319                         break;
2320                 case OP_X86_INC_REG:
2321                         x86_inc_reg (code, ins->dreg);
2322                         break;
2323                 case OP_X86_DEC_MEMBASE:
2324                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2325                         break;
2326                 case OP_X86_DEC_REG:
2327                         x86_dec_reg (code, ins->dreg);
2328                         break;
2329                 case OP_X86_MUL_REG_MEMBASE:
2330                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2331                         break;
2332                 case OP_X86_AND_REG_MEMBASE:
2333                         x86_alu_reg_membase (code, X86_AND, ins->sreg1, ins->sreg2, ins->inst_offset);
2334                         break;
2335                 case OP_X86_OR_REG_MEMBASE:
2336                         x86_alu_reg_membase (code, X86_OR, ins->sreg1, ins->sreg2, ins->inst_offset);
2337                         break;
2338                 case OP_X86_XOR_REG_MEMBASE:
2339                         x86_alu_reg_membase (code, X86_XOR, ins->sreg1, ins->sreg2, ins->inst_offset);
2340                         break;
2341                 case OP_BREAK:
2342                         x86_breakpoint (code);
2343                         break;
2344                 case OP_RELAXED_NOP:
2345                         x86_prefix (code, X86_REP_PREFIX);
2346                         x86_nop (code);
2347                         break;
2348                 case OP_HARD_NOP:
2349                         x86_nop (code);
2350                         break;
2351                 case OP_NOP:
2352                 case OP_DUMMY_USE:
2353                 case OP_DUMMY_STORE:
2354                 case OP_NOT_REACHED:
2355                 case OP_NOT_NULL:
2356                         break;
2357                 case OP_SEQ_POINT: {
2358                         int i, il_offset;
2359
2360                         /* 
2361                          * Read from the single stepping trigger page. This will cause a
2362                          * SIGSEGV when single stepping is enabled.
2363                          * We do this _before_ the breakpoint, so single stepping after
2364                          * a breakpoint is hit will step to the next IL offset.
2365                          */
2366                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
2367                                 x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
2368
2369                         il_offset = ins->inst_imm;
2370
2371                         if (!cfg->seq_points)
2372                                 cfg->seq_points = g_ptr_array_new ();
2373                         g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
2374                         g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
2375                         /* 
2376                          * A placeholder for a possible breakpoint inserted by
2377                          * mono_arch_set_breakpoint ().
2378                          */
2379                         for (i = 0; i < 6; ++i)
2380                                 x86_nop (code);
2381                         break;
2382                 }
2383                 case OP_ADDCC:
2384                 case OP_IADDCC:
2385                 case OP_IADD:
2386                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2387                         break;
2388                 case OP_ADC:
2389                 case OP_IADC:
2390                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2391                         break;
2392                 case OP_ADDCC_IMM:
2393                 case OP_ADD_IMM:
2394                 case OP_IADD_IMM:
2395                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2396                         break;
2397                 case OP_ADC_IMM:
2398                 case OP_IADC_IMM:
2399                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2400                         break;
2401                 case OP_SUBCC:
2402                 case OP_ISUBCC:
2403                 case OP_ISUB:
2404                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2405                         break;
2406                 case OP_SBB:
2407                 case OP_ISBB:
2408                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2409                         break;
2410                 case OP_SUBCC_IMM:
2411                 case OP_SUB_IMM:
2412                 case OP_ISUB_IMM:
2413                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2414                         break;
2415                 case OP_SBB_IMM:
2416                 case OP_ISBB_IMM:
2417                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2418                         break;
2419                 case OP_IAND:
2420                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2421                         break;
2422                 case OP_AND_IMM:
2423                 case OP_IAND_IMM:
2424                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2425                         break;
2426                 case OP_IDIV:
2427                 case OP_IREM:
2428                         /* 
2429                          * The code is the same for div/rem, the allocator will allocate dreg
2430                          * to RAX/RDX as appropriate.
2431                          */
2432                         if (ins->sreg2 == X86_EDX) {
2433                                 /* cdq clobbers this */
2434                                 x86_push_reg (code, ins->sreg2);
2435                                 x86_cdq (code);
2436                                 x86_div_membase (code, X86_ESP, 0, TRUE);
2437                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2438                         } else {
2439                                 x86_cdq (code);
2440                                 x86_div_reg (code, ins->sreg2, TRUE);
2441                         }
2442                         break;
2443                 case OP_IDIV_UN:
2444                 case OP_IREM_UN:
2445                         if (ins->sreg2 == X86_EDX) {
2446                                 x86_push_reg (code, ins->sreg2);
2447                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2448                                 x86_div_membase (code, X86_ESP, 0, FALSE);
2449                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2450                         } else {
2451                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2452                                 x86_div_reg (code, ins->sreg2, FALSE);
2453                         }
2454                         break;
2455                 case OP_DIV_IMM:
2456                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2457                         x86_cdq (code);
2458                         x86_div_reg (code, ins->sreg2, TRUE);
2459                         break;
2460                 case OP_IREM_IMM: {
2461                         int power = mono_is_power_of_two (ins->inst_imm);
2462
2463                         g_assert (ins->sreg1 == X86_EAX);
2464                         g_assert (ins->dreg == X86_EAX);
2465                         g_assert (power >= 0);
2466
2467                         if (power == 1) {
2468                                 /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */
2469                                 x86_cdq (code);
2470                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
2471                                 /* 
2472                                  * If the divident is >= 0, this does not nothing. If it is positive, it
2473                                  * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1.
2474                                  */
2475                                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EDX);
2476                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2477                         } else if (power == 0) {
2478                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
2479                         } else {
2480                                 /* Based on gcc code */
2481
2482                                 /* Add compensation for negative dividents */
2483                                 x86_cdq (code);
2484                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 - power);
2485                                 x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EDX);
2486                                 /* Compute remainder */
2487                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 << power) - 1);
2488                                 /* Remove compensation */
2489                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2490                         }
2491                         break;
2492                 }
2493                 case OP_IOR:
2494                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2495                         break;
2496                 case OP_OR_IMM:
2497                 case OP_IOR_IMM:
2498                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2499                         break;
2500                 case OP_IXOR:
2501                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2502                         break;
2503                 case OP_XOR_IMM:
2504                 case OP_IXOR_IMM:
2505                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2506                         break;
2507                 case OP_ISHL:
2508                         g_assert (ins->sreg2 == X86_ECX);
2509                         x86_shift_reg (code, X86_SHL, ins->dreg);
2510                         break;
2511                 case OP_ISHR:
2512                         g_assert (ins->sreg2 == X86_ECX);
2513                         x86_shift_reg (code, X86_SAR, ins->dreg);
2514                         break;
2515                 case OP_SHR_IMM:
2516                 case OP_ISHR_IMM:
2517                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2518                         break;
2519                 case OP_SHR_UN_IMM:
2520                 case OP_ISHR_UN_IMM:
2521                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2522                         break;
2523                 case OP_ISHR_UN:
2524                         g_assert (ins->sreg2 == X86_ECX);
2525                         x86_shift_reg (code, X86_SHR, ins->dreg);
2526                         break;
2527                 case OP_SHL_IMM:
2528                 case OP_ISHL_IMM:
2529                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2530                         break;
2531                 case OP_LSHL: {
2532                         guint8 *jump_to_end;
2533
2534                         /* handle shifts below 32 bits */
2535                         x86_shld_reg (code, ins->backend.reg3, ins->sreg1);
2536                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2537
2538                         x86_test_reg_imm (code, X86_ECX, 32);
2539                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2540
2541                         /* handle shift over 32 bit */
2542                         x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2543                         x86_clear_reg (code, ins->sreg1);
2544                         
2545                         x86_patch (jump_to_end, code);
2546                         }
2547                         break;
2548                 case OP_LSHR: {
2549                         guint8 *jump_to_end;
2550
2551                         /* handle shifts below 32 bits */
2552                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2553                         x86_shift_reg (code, X86_SAR, ins->backend.reg3);
2554
2555                         x86_test_reg_imm (code, X86_ECX, 32);
2556                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2557
2558                         /* handle shifts over 31 bits */
2559                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2560                         x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31);
2561                         
2562                         x86_patch (jump_to_end, code);
2563                         }
2564                         break;
2565                 case OP_LSHR_UN: {
2566                         guint8 *jump_to_end;
2567
2568                         /* handle shifts below 32 bits */
2569                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2570                         x86_shift_reg (code, X86_SHR, ins->backend.reg3);
2571
2572                         x86_test_reg_imm (code, X86_ECX, 32);
2573                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2574
2575                         /* handle shifts over 31 bits */
2576                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2577                         x86_clear_reg (code, ins->backend.reg3);
2578                         
2579                         x86_patch (jump_to_end, code);
2580                         }
2581                         break;
2582                 case OP_LSHL_IMM:
2583                         if (ins->inst_imm >= 32) {
2584                                 x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2585                                 x86_clear_reg (code, ins->sreg1);
2586                                 x86_shift_reg_imm (code, X86_SHL, ins->backend.reg3, ins->inst_imm - 32);
2587                         } else {
2588                                 x86_shld_reg_imm (code, ins->backend.reg3, ins->sreg1, ins->inst_imm);
2589                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
2590                         }
2591                         break;
2592                 case OP_LSHR_IMM:
2593                         if (ins->inst_imm >= 32) {
2594                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3,  4);
2595                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 0x1f);
2596                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
2597                         } else {
2598                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2599                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, ins->inst_imm);
2600                         }
2601                         break;
2602                 case OP_LSHR_UN_IMM:
2603                         if (ins->inst_imm >= 32) {
2604                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2605                                 x86_clear_reg (code, ins->backend.reg3);
2606                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
2607                         } else {
2608                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2609                                 x86_shift_reg_imm (code, X86_SHR, ins->backend.reg3, ins->inst_imm);
2610                         }
2611                         break;
2612                 case OP_INOT:
2613                         x86_not_reg (code, ins->sreg1);
2614                         break;
2615                 case OP_INEG:
2616                         x86_neg_reg (code, ins->sreg1);
2617                         break;
2618
2619                 case OP_IMUL:
2620                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2621                         break;
2622                 case OP_MUL_IMM:
2623                 case OP_IMUL_IMM:
2624                         switch (ins->inst_imm) {
2625                         case 2:
2626                                 /* MOV r1, r2 */
2627                                 /* ADD r1, r1 */
2628                                 if (ins->dreg != ins->sreg1)
2629                                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2630                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2631                                 break;
2632                         case 3:
2633                                 /* LEA r1, [r2 + r2*2] */
2634                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2635                                 break;
2636                         case 5:
2637                                 /* LEA r1, [r2 + r2*4] */
2638                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2639                                 break;
2640                         case 6:
2641                                 /* LEA r1, [r2 + r2*2] */
2642                                 /* ADD r1, r1          */
2643                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2644                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2645                                 break;
2646                         case 9:
2647                                 /* LEA r1, [r2 + r2*8] */
2648                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
2649                                 break;
2650                         case 10:
2651                                 /* LEA r1, [r2 + r2*4] */
2652                                 /* ADD r1, r1          */
2653                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2654                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2655                                 break;
2656                         case 12:
2657                                 /* LEA r1, [r2 + r2*2] */
2658                                 /* SHL r1, 2           */
2659                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2660                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2661                                 break;
2662                         case 25:
2663                                 /* LEA r1, [r2 + r2*4] */
2664                                 /* LEA r1, [r1 + r1*4] */
2665                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2666                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2667                                 break;
2668                         case 100:
2669                                 /* LEA r1, [r2 + r2*4] */
2670                                 /* SHL r1, 2           */
2671                                 /* LEA r1, [r1 + r1*4] */
2672                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2673                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2674                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2675                                 break;
2676                         default:
2677                                 x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2678                                 break;
2679                         }
2680                         break;
2681                 case OP_IMUL_OVF:
2682                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2683                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2684                         break;
2685                 case OP_IMUL_OVF_UN: {
2686                         /* the mul operation and the exception check should most likely be split */
2687                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
2688                         /*g_assert (ins->sreg2 == X86_EAX);
2689                         g_assert (ins->dreg == X86_EAX);*/
2690                         if (ins->sreg2 == X86_EAX) {
2691                                 non_eax_reg = ins->sreg1;
2692                         } else if (ins->sreg1 == X86_EAX) {
2693                                 non_eax_reg = ins->sreg2;
2694                         } else {
2695                                 /* no need to save since we're going to store to it anyway */
2696                                 if (ins->dreg != X86_EAX) {
2697                                         saved_eax = TRUE;
2698                                         x86_push_reg (code, X86_EAX);
2699                                 }
2700                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
2701                                 non_eax_reg = ins->sreg2;
2702                         }
2703                         if (ins->dreg == X86_EDX) {
2704                                 if (!saved_eax) {
2705                                         saved_eax = TRUE;
2706                                         x86_push_reg (code, X86_EAX);
2707                                 }
2708                         } else if (ins->dreg != X86_EAX) {
2709                                 saved_edx = TRUE;
2710                                 x86_push_reg (code, X86_EDX);
2711                         }
2712                         x86_mul_reg (code, non_eax_reg, FALSE);
2713                         /* save before the check since pop and mov don't change the flags */
2714                         if (ins->dreg != X86_EAX)
2715                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2716                         if (saved_edx)
2717                                 x86_pop_reg (code, X86_EDX);
2718                         if (saved_eax)
2719                                 x86_pop_reg (code, X86_EAX);
2720                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2721                         break;
2722                 }
2723                 case OP_ICONST:
2724                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
2725                         break;
2726                 case OP_AOTCONST:
2727                         g_assert_not_reached ();
2728                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2729                         x86_mov_reg_imm (code, ins->dreg, 0);
2730                         break;
2731                 case OP_JUMP_TABLE:
2732                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2733                         x86_mov_reg_imm (code, ins->dreg, 0);
2734                         break;
2735                 case OP_LOAD_GOTADDR:
2736                         x86_call_imm (code, 0);
2737                         /* 
2738                          * The patch needs to point to the pop, since the GOT offset needs 
2739                          * to be added to that address.
2740                          */
2741                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
2742                         x86_pop_reg (code, ins->dreg);
2743                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, 0xf0f0f0f0);
2744                         break;
2745                 case OP_GOT_ENTRY:
2746                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2747                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, 0xf0f0f0f0, 4);
2748                         break;
2749                 case OP_X86_PUSH_GOT_ENTRY:
2750                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2751                         x86_push_membase (code, ins->inst_basereg, 0xf0f0f0f0);
2752                         break;
2753                 case OP_MOVE:
2754                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2755                         break;
2756                 case OP_JMP: {
2757                         /*
2758                          * Note: this 'frame destruction' logic is useful for tail calls, too.
2759                          * Keep in sync with the code in emit_epilog.
2760                          */
2761                         int pos = 0;
2762
2763                         /* FIXME: no tracing support... */
2764                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2765                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
2766                         /* reset offset to make max_len work */
2767                         offset = code - cfg->native_code;
2768
2769                         g_assert (!cfg->method->save_lmf);
2770
2771                         code = emit_load_volatile_arguments (cfg, code);
2772
2773                         if (cfg->used_int_regs & (1 << X86_EBX))
2774                                 pos -= 4;
2775                         if (cfg->used_int_regs & (1 << X86_EDI))
2776                                 pos -= 4;
2777                         if (cfg->used_int_regs & (1 << X86_ESI))
2778                                 pos -= 4;
2779                         if (pos)
2780                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
2781         
2782                         if (cfg->used_int_regs & (1 << X86_ESI))
2783                                 x86_pop_reg (code, X86_ESI);
2784                         if (cfg->used_int_regs & (1 << X86_EDI))
2785                                 x86_pop_reg (code, X86_EDI);
2786                         if (cfg->used_int_regs & (1 << X86_EBX))
2787                                 x86_pop_reg (code, X86_EBX);
2788         
2789                         /* restore ESP/EBP */
2790                         x86_leave (code);
2791                         offset = code - cfg->native_code;
2792                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2793                         x86_jump32 (code, 0);
2794
2795                         cfg->disable_aot = TRUE;
2796                         break;
2797                 }
2798                 case OP_CHECK_THIS:
2799                         /* ensure ins->sreg1 is not NULL
2800                          * note that cmp DWORD PTR [eax], eax is one byte shorter than
2801                          * cmp DWORD PTR [eax], 0
2802                          */
2803                         x86_alu_membase_reg (code, X86_CMP, ins->sreg1, 0, ins->sreg1);
2804                         break;
2805                 case OP_ARGLIST: {
2806                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
2807                         x86_push_reg (code, hreg);
2808                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
2809                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
2810                         x86_pop_reg (code, hreg);
2811                         break;
2812                 }
2813                 case OP_FCALL:
2814                 case OP_LCALL:
2815                 case OP_VCALL:
2816                 case OP_VCALL2:
2817                 case OP_VOIDCALL:
2818                 case OP_CALL:
2819                         call = (MonoCallInst*)ins;
2820                         if (ins->flags & MONO_INST_HAS_METHOD)
2821                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2822                         else
2823                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2824                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2825                                 /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8
2826                                  * bytes to pop, we want to use pops. GCC does this (note it won't happen
2827                                  * for P4 or i686 because gcc will avoid using pop push at all. But we aren't
2828                                  * smart enough to do that optimization yet
2829                                  *
2830                                  * It turns out that on my P4, doing two pops for 8 bytes on the stack makes
2831                                  * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small,
2832                                  * (most likely from locality benefits). People with other processors should
2833                                  * check on theirs to see what happens.
2834                                  */
2835                                 if (call->stack_usage == 4) {
2836                                         /* we want to use registers that won't get used soon, so use
2837                                          * ecx, as eax will get allocated first. edx is used by long calls,
2838                                          * so we can't use that.
2839                                          */
2840                                         
2841                                         x86_pop_reg (code, X86_ECX);
2842                                 } else {
2843                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2844                                 }
2845                         }
2846                         code = emit_move_return_value (cfg, ins, code);
2847                         break;
2848                 case OP_FCALL_REG:
2849                 case OP_LCALL_REG:
2850                 case OP_VCALL_REG:
2851                 case OP_VCALL2_REG:
2852                 case OP_VOIDCALL_REG:
2853                 case OP_CALL_REG:
2854                         call = (MonoCallInst*)ins;
2855                         x86_call_reg (code, ins->sreg1);
2856                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2857                                 if (call->stack_usage == 4)
2858                                         x86_pop_reg (code, X86_ECX);
2859                                 else
2860                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2861                         }
2862                         code = emit_move_return_value (cfg, ins, code);
2863                         break;
2864                 case OP_FCALL_MEMBASE:
2865                 case OP_LCALL_MEMBASE:
2866                 case OP_VCALL_MEMBASE:
2867                 case OP_VCALL2_MEMBASE:
2868                 case OP_VOIDCALL_MEMBASE:
2869                 case OP_CALL_MEMBASE:
2870                         call = (MonoCallInst*)ins;
2871
2872                         /* 
2873                          * Emit a few nops to simplify get_vcall_slot ().
2874                          */
2875                         x86_nop (code);
2876                         x86_nop (code);
2877                         x86_nop (code);
2878
2879                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
2880                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2881                                 if (call->stack_usage == 4)
2882                                         x86_pop_reg (code, X86_ECX);
2883                                 else
2884                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2885                         }
2886                         code = emit_move_return_value (cfg, ins, code);
2887                         break;
2888                 case OP_X86_PUSH:
2889                         x86_push_reg (code, ins->sreg1);
2890                         break;
2891                 case OP_X86_PUSH_IMM:
2892                         x86_push_imm (code, ins->inst_imm);
2893                         break;
2894                 case OP_X86_PUSH_MEMBASE:
2895                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
2896                         break;
2897                 case OP_X86_PUSH_OBJ: 
2898                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
2899                         x86_push_reg (code, X86_EDI);
2900                         x86_push_reg (code, X86_ESI);
2901                         x86_push_reg (code, X86_ECX);
2902                         if (ins->inst_offset)
2903                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
2904                         else
2905                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
2906                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2907                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
2908                         x86_cld (code);
2909                         x86_prefix (code, X86_REP_PREFIX);
2910                         x86_movsd (code);
2911                         x86_pop_reg (code, X86_ECX);
2912                         x86_pop_reg (code, X86_ESI);
2913                         x86_pop_reg (code, X86_EDI);
2914                         break;
2915                 case OP_X86_LEA:
2916                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
2917                         break;
2918                 case OP_X86_LEA_MEMBASE:
2919                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
2920                         break;
2921                 case OP_X86_XCHG:
2922                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
2923                         break;
2924                 case OP_LOCALLOC:
2925                         /* keep alignment */
2926                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1);
2927                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2928                         code = mono_emit_stack_alloc (code, ins);
2929                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2930                         break;
2931                 case OP_LOCALLOC_IMM: {
2932                         guint32 size = ins->inst_imm;
2933                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2934
2935                         if (ins->flags & MONO_INST_INIT) {
2936                                 /* FIXME: Optimize this */
2937                                 x86_mov_reg_imm (code, ins->dreg, size);
2938                                 ins->sreg1 = ins->dreg;
2939
2940                                 code = mono_emit_stack_alloc (code, ins);
2941                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2942                         } else {
2943                                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, size);
2944                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2945                         }
2946                         break;
2947                 }
2948                 case OP_THROW: {
2949                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2950                         x86_push_reg (code, ins->sreg1);
2951                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2952                                                           (gpointer)"mono_arch_throw_exception");
2953                         break;
2954                 }
2955                 case OP_RETHROW: {
2956                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2957                         x86_push_reg (code, ins->sreg1);
2958                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2959                                                           (gpointer)"mono_arch_rethrow_exception");
2960                         break;
2961                 }
2962                 case OP_CALL_HANDLER:
2963                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2964                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2965                         x86_call_imm (code, 0);
2966                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2967                         break;
2968                 case OP_START_HANDLER: {
2969                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2970                         x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
2971                         break;
2972                 }
2973                 case OP_ENDFINALLY: {
2974                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2975                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2976                         x86_ret (code);
2977                         break;
2978                 }
2979                 case OP_ENDFILTER: {
2980                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2981                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2982                         /* The local allocator will put the result into EAX */
2983                         x86_ret (code);
2984                         break;
2985                 }
2986
2987                 case OP_LABEL:
2988                         ins->inst_c0 = code - cfg->native_code;
2989                         break;
2990                 case OP_BR:
2991                         if (ins->inst_target_bb->native_offset) {
2992                                 x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2993                         } else {
2994                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2995                                 if ((cfg->opt & MONO_OPT_BRANCH) &&
2996                                     x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
2997                                         x86_jump8 (code, 0);
2998                                 else 
2999                                         x86_jump32 (code, 0);
3000                         }
3001                         break;
3002                 case OP_BR_REG:
3003                         x86_jump_reg (code, ins->sreg1);
3004                         break;
3005                 case OP_CEQ:
3006                 case OP_CLT:
3007                 case OP_CLT_UN:
3008                 case OP_CGT:
3009                 case OP_CGT_UN:
3010                 case OP_CNE:
3011                 case OP_ICEQ:
3012                 case OP_ICLT:
3013                 case OP_ICLT_UN:
3014                 case OP_ICGT:
3015                 case OP_ICGT_UN:
3016                         x86_set_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3017                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3018                         break;
3019                 case OP_COND_EXC_EQ:
3020                 case OP_COND_EXC_NE_UN:
3021                 case OP_COND_EXC_LT:
3022                 case OP_COND_EXC_LT_UN:
3023                 case OP_COND_EXC_GT:
3024                 case OP_COND_EXC_GT_UN:
3025                 case OP_COND_EXC_GE:
3026                 case OP_COND_EXC_GE_UN:
3027                 case OP_COND_EXC_LE:
3028                 case OP_COND_EXC_LE_UN:
3029                 case OP_COND_EXC_IEQ:
3030                 case OP_COND_EXC_INE_UN:
3031                 case OP_COND_EXC_ILT:
3032                 case OP_COND_EXC_ILT_UN:
3033                 case OP_COND_EXC_IGT:
3034                 case OP_COND_EXC_IGT_UN:
3035                 case OP_COND_EXC_IGE:
3036                 case OP_COND_EXC_IGE_UN:
3037                 case OP_COND_EXC_ILE:
3038                 case OP_COND_EXC_ILE_UN:
3039                         EMIT_COND_SYSTEM_EXCEPTION (cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->inst_p1);
3040                         break;
3041                 case OP_COND_EXC_OV:
3042                 case OP_COND_EXC_NO:
3043                 case OP_COND_EXC_C:
3044                 case OP_COND_EXC_NC:
3045                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
3046                         break;
3047                 case OP_COND_EXC_IOV:
3048                 case OP_COND_EXC_INO:
3049                 case OP_COND_EXC_IC:
3050                 case OP_COND_EXC_INC:
3051                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), ins->inst_p1);
3052                         break;
3053                 case OP_IBEQ:
3054                 case OP_IBNE_UN:
3055                 case OP_IBLT:
3056                 case OP_IBLT_UN:
3057                 case OP_IBGT:
3058                 case OP_IBGT_UN:
3059                 case OP_IBGE:
3060                 case OP_IBGE_UN:
3061                 case OP_IBLE:
3062                 case OP_IBLE_UN:
3063                         EMIT_COND_BRANCH (ins, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3064                         break;
3065
3066                 case OP_CMOV_IEQ:
3067                 case OP_CMOV_IGE:
3068                 case OP_CMOV_IGT:
3069                 case OP_CMOV_ILE:
3070                 case OP_CMOV_ILT:
3071                 case OP_CMOV_INE_UN:
3072                 case OP_CMOV_IGE_UN:
3073                 case OP_CMOV_IGT_UN:
3074                 case OP_CMOV_ILE_UN:
3075                 case OP_CMOV_ILT_UN:
3076                         g_assert (ins->dreg == ins->sreg1);
3077                         x86_cmov_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, ins->sreg2);
3078                         break;
3079
3080                 /* floating point opcodes */
3081                 case OP_R8CONST: {
3082                         double d = *(double *)ins->inst_p0;
3083
3084                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
3085                                 x86_fldz (code);
3086                         } else if (d == 1.0) {
3087                                 x86_fld1 (code);
3088                         } else {
3089                                 if (cfg->compile_aot) {
3090                                         guint32 *val = (guint32*)&d;
3091                                         x86_push_imm (code, val [1]);
3092                                         x86_push_imm (code, val [0]);
3093                                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3094                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3095                                 }
3096                                 else {
3097                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R8, ins->inst_p0);
3098                                         x86_fld (code, NULL, TRUE);
3099                                 }
3100                         }
3101                         break;
3102                 }
3103                 case OP_R4CONST: {
3104                         float f = *(float *)ins->inst_p0;
3105
3106                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
3107                                 x86_fldz (code);
3108                         } else if (f == 1.0) {
3109                                 x86_fld1 (code);
3110                         } else {
3111                                 if (cfg->compile_aot) {
3112                                         guint32 val = *(guint32*)&f;
3113                                         x86_push_imm (code, val);
3114                                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3115                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3116                                 }
3117                                 else {
3118                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R4, ins->inst_p0);
3119                                         x86_fld (code, NULL, FALSE);
3120                                 }
3121                         }
3122                         break;
3123                 }
3124                 case OP_STORER8_MEMBASE_REG:
3125                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
3126                         break;
3127                 case OP_LOADR8_MEMBASE:
3128                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3129                         break;
3130                 case OP_STORER4_MEMBASE_REG:
3131                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
3132                         break;
3133                 case OP_LOADR4_MEMBASE:
3134                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3135                         break;
3136                 case OP_ICONV_TO_R4:
3137                         x86_push_reg (code, ins->sreg1);
3138                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3139                         /* Change precision */
3140                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3141                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3142                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3143                         break;
3144                 case OP_ICONV_TO_R8:
3145                         x86_push_reg (code, ins->sreg1);
3146                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3147                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3148                         break;
3149                 case OP_ICONV_TO_R_UN:
3150                         x86_push_imm (code, 0);
3151                         x86_push_reg (code, ins->sreg1);
3152                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3153                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3154                         break;
3155                 case OP_X86_FP_LOAD_I8:
3156                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3157                         break;
3158                 case OP_X86_FP_LOAD_I4:
3159                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3160                         break;
3161                 case OP_FCONV_TO_R4:
3162                         /* Change precision */
3163                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3164                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3165                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3166                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3167                         break;
3168                 case OP_FCONV_TO_I1:
3169                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
3170                         break;
3171                 case OP_FCONV_TO_U1:
3172                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
3173                         break;
3174                 case OP_FCONV_TO_I2:
3175                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
3176                         break;
3177                 case OP_FCONV_TO_U2:
3178                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
3179                         break;
3180                 case OP_FCONV_TO_I4:
3181                 case OP_FCONV_TO_I:
3182                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
3183                         break;
3184                 case OP_FCONV_TO_I8:
3185                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3186                         x86_fnstcw_membase(code, X86_ESP, 0);
3187                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
3188                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
3189                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
3190                         x86_fldcw_membase (code, X86_ESP, 2);
3191                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3192                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
3193                         x86_pop_reg (code, ins->dreg);
3194                         x86_pop_reg (code, ins->backend.reg3);
3195                         x86_fldcw_membase (code, X86_ESP, 0);
3196                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3197                         break;
3198                 case OP_LCONV_TO_R8_2:
3199                         x86_push_reg (code, ins->sreg2);
3200                         x86_push_reg (code, ins->sreg1);
3201                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3202                         /* Change precision */
3203                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3204                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3205                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3206                         break;
3207                 case OP_LCONV_TO_R4_2:
3208                         x86_push_reg (code, ins->sreg2);
3209                         x86_push_reg (code, ins->sreg1);
3210                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3211                         /* Change precision */
3212                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3213                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3214                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3215                         break;
3216                 case OP_LCONV_TO_R_UN_2: { 
3217                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3218                         guint8 *br;
3219
3220                         /* load 64bit integer to FP stack */
3221                         x86_push_reg (code, ins->sreg2);
3222                         x86_push_reg (code, ins->sreg1);
3223                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3224                         
3225                         /* test if lreg is negative */
3226                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3227                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
3228         
3229                         /* add correction constant mn */
3230                         x86_fld80_mem (code, mn);
3231                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3232
3233                         x86_patch (br, code);
3234
3235                         /* Change precision */
3236                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3237                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3238
3239                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3240
3241                         break;
3242                 }
3243                 case OP_LCONV_TO_OVF_I:
3244                 case OP_LCONV_TO_OVF_I4_2: {
3245                         guint8 *br [3], *label [1];
3246                         MonoInst *tins;
3247
3248                         /* 
3249                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3250                          */
3251                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
3252
3253                         /* If the low word top bit is set, see if we are negative */
3254                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
3255                         /* We are not negative (no top bit set, check for our top word to be zero */
3256                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3257                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
3258                         label [0] = code;
3259
3260                         /* throw exception */
3261                         tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
3262                         if (tins) {
3263                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
3264                                 if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
3265                                         x86_jump8 (code, 0);
3266                                 else
3267                                         x86_jump32 (code, 0);
3268                         } else {
3269                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
3270                                 x86_jump32 (code, 0);
3271                         }
3272         
3273         
3274                         x86_patch (br [0], code);
3275                         /* our top bit is set, check that top word is 0xfffffff */
3276                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
3277                 
3278                         x86_patch (br [1], code);
3279                         /* nope, emit exception */
3280                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
3281                         x86_patch (br [2], label [0]);
3282
3283                         if (ins->dreg != ins->sreg1)
3284                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3285                         break;
3286                 }
3287                 case OP_FMOVE:
3288                         /* Not needed on the fp stack */
3289                         break;
3290                 case OP_FADD:
3291                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3292                         break;
3293                 case OP_FSUB:
3294                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
3295                         break;          
3296                 case OP_FMUL:
3297                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
3298                         break;          
3299                 case OP_FDIV:
3300                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
3301                         break;          
3302                 case OP_FNEG:
3303                         x86_fchs (code);
3304                         break;          
3305                 case OP_SIN:
3306                         x86_fsin (code);
3307                         x86_fldz (code);
3308                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3309                         break;          
3310                 case OP_COS:
3311                         x86_fcos (code);
3312                         x86_fldz (code);
3313                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3314                         break;          
3315                 case OP_ABS:
3316                         x86_fabs (code);
3317                         break;          
3318                 case OP_TAN: {
3319                         /* 
3320                          * it really doesn't make sense to inline all this code,
3321                          * it's here just to show that things may not be as simple 
3322                          * as they appear.
3323                          */
3324                         guchar *check_pos, *end_tan, *pop_jump;
3325                         x86_push_reg (code, X86_EAX);
3326                         x86_fptan (code);
3327                         x86_fnstsw (code);
3328                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3329                         check_pos = code;
3330                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3331                         x86_fstp (code, 0); /* pop the 1.0 */
3332                         end_tan = code;
3333                         x86_jump8 (code, 0);
3334                         x86_fldpi (code);
3335                         x86_fp_op (code, X86_FADD, 0);
3336                         x86_fxch (code, 1);
3337                         x86_fprem1 (code);
3338                         x86_fstsw (code);
3339                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3340                         pop_jump = code;
3341                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3342                         x86_fstp (code, 1);
3343                         x86_fptan (code);
3344                         x86_patch (pop_jump, code);
3345                         x86_fstp (code, 0); /* pop the 1.0 */
3346                         x86_patch (check_pos, code);
3347                         x86_patch (end_tan, code);
3348                         x86_fldz (code);
3349                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3350                         x86_pop_reg (code, X86_EAX);
3351                         break;
3352                 }
3353                 case OP_ATAN:
3354                         x86_fld1 (code);
3355                         x86_fpatan (code);
3356                         x86_fldz (code);
3357                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3358                         break;          
3359                 case OP_SQRT:
3360                         x86_fsqrt (code);
3361                         break;
3362                 case OP_ROUND:
3363                         x86_frndint (code);
3364                         break;
3365                 case OP_IMIN:
3366                         g_assert (cfg->opt & MONO_OPT_CMOV);
3367                         g_assert (ins->dreg == ins->sreg1);
3368                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3369                         x86_cmov_reg (code, X86_CC_GT, TRUE, ins->dreg, ins->sreg2);
3370                         break;
3371                 case OP_IMIN_UN:
3372                         g_assert (cfg->opt & MONO_OPT_CMOV);
3373                         g_assert (ins->dreg == ins->sreg1);
3374                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3375                         x86_cmov_reg (code, X86_CC_GT, FALSE, ins->dreg, ins->sreg2);
3376                         break;
3377                 case OP_IMAX:
3378                         g_assert (cfg->opt & MONO_OPT_CMOV);
3379                         g_assert (ins->dreg == ins->sreg1);
3380                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3381                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
3382                         break;
3383                 case OP_IMAX_UN:
3384                         g_assert (cfg->opt & MONO_OPT_CMOV);
3385                         g_assert (ins->dreg == ins->sreg1);
3386                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3387                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
3388                         break;
3389                 case OP_X86_FPOP:
3390                         x86_fstp (code, 0);
3391                         break;
3392                 case OP_X86_FXCH:
3393                         x86_fxch (code, ins->inst_imm);
3394                         break;
3395                 case OP_FREM: {
3396                         guint8 *l1, *l2;
3397
3398                         x86_push_reg (code, X86_EAX);
3399                         /* we need to exchange ST(0) with ST(1) */
3400                         x86_fxch (code, 1);
3401
3402                         /* this requires a loop, because fprem somtimes 
3403                          * returns a partial remainder */
3404                         l1 = code;
3405                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3406                         /* x86_fprem1 (code); */
3407                         x86_fprem (code);
3408                         x86_fnstsw (code);
3409                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3410                         l2 = code + 2;
3411                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3412
3413                         /* pop result */
3414                         x86_fstp (code, 1);
3415
3416                         x86_pop_reg (code, X86_EAX);
3417                         break;
3418                 }
3419                 case OP_FCOMPARE:
3420                         if (cfg->opt & MONO_OPT_FCMOV) {
3421                                 x86_fcomip (code, 1);
3422                                 x86_fstp (code, 0);
3423                                 break;
3424                         }
3425                         /* this overwrites EAX */
3426                         EMIT_FPCOMPARE(code);
3427                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3428                         break;
3429                 case OP_FCEQ:
3430                         if (cfg->opt & MONO_OPT_FCMOV) {
3431                                 /* zeroing the register at the start results in 
3432                                  * shorter and faster code (we can also remove the widening op)
3433                                  */
3434                                 guchar *unordered_check;
3435                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3436                                 x86_fcomip (code, 1);
3437                                 x86_fstp (code, 0);
3438                                 unordered_check = code;
3439                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3440                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3441                                 x86_patch (unordered_check, code);
3442                                 break;
3443                         }
3444                         if (ins->dreg != X86_EAX) 
3445                                 x86_push_reg (code, X86_EAX);
3446
3447                         EMIT_FPCOMPARE(code);
3448                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3449                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3450                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3451                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3452
3453                         if (ins->dreg != X86_EAX) 
3454                                 x86_pop_reg (code, X86_EAX);
3455                         break;
3456                 case OP_FCLT:
3457                 case OP_FCLT_UN:
3458                         if (cfg->opt & MONO_OPT_FCMOV) {
3459                                 /* zeroing the register at the start results in 
3460                                  * shorter and faster code (we can also remove the widening op)
3461                                  */
3462                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3463                                 x86_fcomip (code, 1);
3464                                 x86_fstp (code, 0);
3465                                 if (ins->opcode == OP_FCLT_UN) {
3466                                         guchar *unordered_check = code;
3467                                         guchar *jump_to_end;
3468                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3469                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3470                                         jump_to_end = code;
3471                                         x86_jump8 (code, 0);
3472                                         x86_patch (unordered_check, code);
3473                                         x86_inc_reg (code, ins->dreg);
3474                                         x86_patch (jump_to_end, code);
3475                                 } else {
3476                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3477                                 }
3478                                 break;
3479                         }
3480                         if (ins->dreg != X86_EAX) 
3481                                 x86_push_reg (code, X86_EAX);
3482
3483                         EMIT_FPCOMPARE(code);
3484                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3485                         if (ins->opcode == OP_FCLT_UN) {
3486                                 guchar *is_not_zero_check, *end_jump;
3487                                 is_not_zero_check = code;
3488                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3489                                 end_jump = code;
3490                                 x86_jump8 (code, 0);
3491                                 x86_patch (is_not_zero_check, code);
3492                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3493
3494                                 x86_patch (end_jump, code);
3495                         }
3496                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3497                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3498
3499                         if (ins->dreg != X86_EAX) 
3500                                 x86_pop_reg (code, X86_EAX);
3501                         break;
3502                 case OP_FCGT:
3503                 case OP_FCGT_UN:
3504                         if (cfg->opt & MONO_OPT_FCMOV) {
3505                                 /* zeroing the register at the start results in 
3506                                  * shorter and faster code (we can also remove the widening op)
3507                                  */
3508                                 guchar *unordered_check;
3509                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3510                                 x86_fcomip (code, 1);
3511                                 x86_fstp (code, 0);
3512                                 if (ins->opcode == OP_FCGT) {
3513                                         unordered_check = code;
3514                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3515                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3516                                         x86_patch (unordered_check, code);
3517                                 } else {
3518                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3519                                 }
3520                                 break;
3521                         }
3522                         if (ins->dreg != X86_EAX) 
3523                                 x86_push_reg (code, X86_EAX);
3524
3525                         EMIT_FPCOMPARE(code);
3526                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3527                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3528                         if (ins->opcode == OP_FCGT_UN) {
3529                                 guchar *is_not_zero_check, *end_jump;
3530                                 is_not_zero_check = code;
3531                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3532                                 end_jump = code;
3533                                 x86_jump8 (code, 0);
3534                                 x86_patch (is_not_zero_check, code);
3535                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3536         
3537                                 x86_patch (end_jump, code);
3538                         }
3539                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3540                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3541
3542                         if (ins->dreg != X86_EAX) 
3543                                 x86_pop_reg (code, X86_EAX);
3544                         break;
3545                 case OP_FBEQ:
3546                         if (cfg->opt & MONO_OPT_FCMOV) {
3547                                 guchar *jump = code;
3548                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3549                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3550                                 x86_patch (jump, code);
3551                                 break;
3552                         }
3553                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3554                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3555                         break;
3556                 case OP_FBNE_UN:
3557                         /* Branch if C013 != 100 */
3558                         if (cfg->opt & MONO_OPT_FCMOV) {
3559                                 /* branch if !ZF or (PF|CF) */
3560                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3561                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3562                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3563                                 break;
3564                         }
3565                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3566                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3567                         break;
3568                 case OP_FBLT:
3569                         if (cfg->opt & MONO_OPT_FCMOV) {
3570                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3571                                 break;
3572                         }
3573                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3574                         break;
3575                 case OP_FBLT_UN:
3576                         if (cfg->opt & MONO_OPT_FCMOV) {
3577                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3578                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3579                                 break;
3580                         }
3581                         if (ins->opcode == OP_FBLT_UN) {
3582                                 guchar *is_not_zero_check, *end_jump;
3583                                 is_not_zero_check = code;
3584                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3585                                 end_jump = code;
3586                                 x86_jump8 (code, 0);
3587                                 x86_patch (is_not_zero_check, code);
3588                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3589
3590                                 x86_patch (end_jump, code);
3591                         }
3592                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3593                         break;
3594                 case OP_FBGT:
3595                 case OP_FBGT_UN:
3596                         if (cfg->opt & MONO_OPT_FCMOV) {
3597                                 if (ins->opcode == OP_FBGT) {
3598                                         guchar *br1;
3599
3600                                         /* skip branch if C1=1 */
3601                                         br1 = code;
3602                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3603                                         /* branch if (C0 | C3) = 1 */
3604                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3605                                         x86_patch (br1, code);
3606                                 } else {
3607                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3608                                 }
3609                                 break;
3610                         }
3611                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3612                         if (ins->opcode == OP_FBGT_UN) {
3613                                 guchar *is_not_zero_check, *end_jump;
3614                                 is_not_zero_check = code;
3615                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3616                                 end_jump = code;
3617                                 x86_jump8 (code, 0);
3618                                 x86_patch (is_not_zero_check, code);
3619                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3620
3621                                 x86_patch (end_jump, code);
3622                         }
3623                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3624                         break;
3625                 case OP_FBGE:
3626                         /* Branch if C013 == 100 or 001 */
3627                         if (cfg->opt & MONO_OPT_FCMOV) {
3628                                 guchar *br1;
3629
3630                                 /* skip branch if C1=1 */
3631                                 br1 = code;
3632                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3633                                 /* branch if (C0 | C3) = 1 */
3634                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3635                                 x86_patch (br1, code);
3636                                 break;
3637                         }
3638                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3639                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3640                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3641                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3642                         break;
3643                 case OP_FBGE_UN:
3644                         /* Branch if C013 == 000 */
3645                         if (cfg->opt & MONO_OPT_FCMOV) {
3646                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3647                                 break;
3648                         }
3649                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3650                         break;
3651                 case OP_FBLE:
3652                         /* Branch if C013=000 or 100 */
3653                         if (cfg->opt & MONO_OPT_FCMOV) {
3654                                 guchar *br1;
3655
3656                                 /* skip branch if C1=1 */
3657                                 br1 = code;
3658                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3659                                 /* branch if C0=0 */
3660                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3661                                 x86_patch (br1, code);
3662                                 break;
3663                         }
3664                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3665                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3666                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3667                         break;
3668                 case OP_FBLE_UN:
3669                         /* Branch if C013 != 001 */
3670                         if (cfg->opt & MONO_OPT_FCMOV) {
3671                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3672                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3673                                 break;
3674                         }
3675                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3676                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3677                         break;
3678                 case OP_CKFINITE: {
3679                         guchar *br1;
3680                         x86_push_reg (code, X86_EAX);
3681                         x86_fxam (code);
3682                         x86_fnstsw (code);
3683                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3684                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3685                         x86_pop_reg (code, X86_EAX);
3686
3687                         /* Have to clean up the fp stack before throwing the exception */
3688                         br1 = code;
3689                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3690
3691                         x86_fstp (code, 0);                     
3692                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3693
3694                         x86_patch (br1, code);
3695                         break;
3696                 }
3697                 case OP_TLS_GET: {
3698                         code = mono_x86_emit_tls_get (code, ins->dreg, ins->inst_offset);
3699                         break;
3700                 }
3701                 case OP_MEMORY_BARRIER: {
3702                         /* Not needed on x86 */
3703                         break;
3704                 }
3705                 case OP_ATOMIC_ADD_I4: {
3706                         int dreg = ins->dreg;
3707
3708                         if (dreg == ins->inst_basereg) {
3709                                 x86_push_reg (code, ins->sreg2);
3710                                 dreg = ins->sreg2;
3711                         } 
3712                         
3713                         if (dreg != ins->sreg2)
3714                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
3715
3716                         x86_prefix (code, X86_LOCK_PREFIX);
3717                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3718
3719                         if (dreg != ins->dreg) {
3720                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3721                                 x86_pop_reg (code, dreg);
3722                         }
3723
3724                         break;
3725                 }
3726                 case OP_ATOMIC_ADD_NEW_I4: {
3727                         int dreg = ins->dreg;
3728
3729                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
3730                         if (ins->sreg2 == dreg) {
3731                                 if (dreg == X86_EBX) {
3732                                         dreg = X86_EDI;
3733                                         if (ins->inst_basereg == X86_EDI)
3734                                                 dreg = X86_ESI;
3735                                 } else {
3736                                         dreg = X86_EBX;
3737                                         if (ins->inst_basereg == X86_EBX)
3738                                                 dreg = X86_EDI;
3739                                 }
3740                         } else if (ins->inst_basereg == dreg) {
3741                                 if (dreg == X86_EBX) {
3742                                         dreg = X86_EDI;
3743                                         if (ins->sreg2 == X86_EDI)
3744                                                 dreg = X86_ESI;
3745                                 } else {
3746                                         dreg = X86_EBX;
3747                                         if (ins->sreg2 == X86_EBX)
3748                                                 dreg = X86_EDI;
3749                                 }
3750                         }
3751
3752                         if (dreg != ins->dreg) {
3753                                 x86_push_reg (code, dreg);
3754                         }
3755
3756                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
3757                         x86_prefix (code, X86_LOCK_PREFIX);
3758                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3759                         /* dreg contains the old value, add with sreg2 value */
3760                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
3761                         
3762                         if (ins->dreg != dreg) {
3763                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3764                                 x86_pop_reg (code, dreg);
3765                         }
3766
3767                         break;
3768                 }
3769                 case OP_ATOMIC_EXCHANGE_I4: {
3770                         guchar *br[2];
3771                         int sreg2 = ins->sreg2;
3772                         int breg = ins->inst_basereg;
3773
3774                         /* cmpxchg uses eax as comperand, need to make sure we can use it
3775                          * hack to overcome limits in x86 reg allocator 
3776                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
3777                          */
3778                         g_assert (ins->dreg == X86_EAX);
3779                         
3780                         /* We need the EAX reg for the cmpxchg */
3781                         if (ins->sreg2 == X86_EAX) {
3782                                 sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX;
3783                                 x86_push_reg (code, sreg2);
3784                                 x86_mov_reg_reg (code, sreg2, X86_EAX, 4);
3785                         }
3786
3787                         if (breg == X86_EAX) {
3788                                 breg = (sreg2 == X86_ESI) ? X86_EDI : X86_ESI;
3789                                 x86_push_reg (code, breg);
3790                                 x86_mov_reg_reg (code, breg, X86_EAX, 4);
3791                         }
3792
3793                         x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
3794
3795                         br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
3796                         x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3797                         br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
3798                         x86_patch (br [1], br [0]);
3799
3800                         if (breg != ins->inst_basereg)
3801                                 x86_pop_reg (code, breg);
3802
3803                         if (ins->sreg2 != sreg2)
3804                                 x86_pop_reg (code, sreg2);
3805
3806                         break;
3807                 }
3808                 case OP_ATOMIC_CAS_I4: {
3809                         g_assert (ins->sreg3 == X86_EAX);
3810                         g_assert (ins->sreg1 != X86_EAX);
3811                         g_assert (ins->sreg1 != ins->sreg2);
3812
3813                         x86_prefix (code, X86_LOCK_PREFIX);
3814                         x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
3815
3816                         if (ins->dreg != X86_EAX)
3817                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
3818                         break;
3819                 }
3820 #ifdef MONO_ARCH_SIMD_INTRINSICS
3821                 case OP_ADDPS:
3822                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
3823                         break;
3824                 case OP_DIVPS:
3825                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
3826                         break;
3827                 case OP_MULPS:
3828                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
3829                         break;
3830                 case OP_SUBPS:
3831                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
3832                         break;
3833                 case OP_MAXPS:
3834                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
3835                         break;
3836                 case OP_MINPS:
3837                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
3838                         break;
3839                 case OP_COMPPS:
3840                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
3841                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
3842                         break;
3843                 case OP_ANDPS:
3844                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
3845                         break;
3846                 case OP_ANDNPS:
3847                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
3848                         break;
3849                 case OP_ORPS:
3850                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
3851                         break;
3852                 case OP_XORPS:
3853                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
3854                         break;
3855                 case OP_SQRTPS:
3856                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
3857                         break;
3858                 case OP_RSQRTPS:
3859                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
3860                         break;
3861                 case OP_RCPPS:
3862                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
3863                         break;
3864                 case OP_ADDSUBPS:
3865                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
3866                         break;
3867                 case OP_HADDPS:
3868                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
3869                         break;
3870                 case OP_HSUBPS:
3871                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
3872                         break;
3873                 case OP_DUPPS_HIGH:
3874                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
3875                         break;
3876                 case OP_DUPPS_LOW:
3877                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
3878                         break;
3879
3880                 case OP_PSHUFLEW_HIGH:
3881                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3882                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
3883                         break;
3884                 case OP_PSHUFLEW_LOW:
3885                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3886                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
3887                         break;
3888                 case OP_PSHUFLED:
3889                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3890                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
3891                         break;
3892
3893                 case OP_ADDPD:
3894                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
3895                         break;
3896                 case OP_DIVPD:
3897                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
3898                         break;
3899                 case OP_MULPD:
3900                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
3901                         break;
3902                 case OP_SUBPD:
3903                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
3904                         break;
3905                 case OP_MAXPD:
3906                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
3907                         break;
3908                 case OP_MINPD:
3909                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
3910                         break;
3911                 case OP_COMPPD:
3912                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
3913                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
3914                         break;
3915                 case OP_ANDPD:
3916                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
3917                         break;
3918                 case OP_ANDNPD:
3919                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
3920                         break;
3921                 case OP_ORPD:
3922                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
3923                         break;
3924                 case OP_XORPD:
3925                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
3926                         break;
3927                 case OP_SQRTPD:
3928                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
3929                         break;
3930                 case OP_ADDSUBPD:
3931                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
3932                         break;
3933                 case OP_HADDPD:
3934                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
3935                         break;
3936                 case OP_HSUBPD:
3937                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
3938                         break;
3939                 case OP_DUPPD:
3940                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
3941                         break;
3942                         
3943                 case OP_EXTRACT_MASK:
3944                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
3945                         break;
3946         
3947                 case OP_PAND:
3948                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
3949                         break;
3950                 case OP_POR:
3951                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
3952                         break;
3953                 case OP_PXOR:
3954                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
3955                         break;
3956
3957                 case OP_PADDB:
3958                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
3959                         break;
3960                 case OP_PADDW:
3961                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
3962                         break;
3963                 case OP_PADDD:
3964                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
3965                         break;
3966                 case OP_PADDQ:
3967                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
3968                         break;
3969
3970                 case OP_PSUBB:
3971                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
3972                         break;
3973                 case OP_PSUBW:
3974                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
3975                         break;
3976                 case OP_PSUBD:
3977                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
3978                         break;
3979                 case OP_PSUBQ:
3980                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
3981                         break;
3982
3983                 case OP_PMAXB_UN:
3984                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
3985                         break;
3986                 case OP_PMAXW_UN:
3987                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
3988                         break;
3989                 case OP_PMAXD_UN:
3990                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
3991                         break;
3992                 
3993                 case OP_PMAXB:
3994                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
3995                         break;
3996                 case OP_PMAXW:
3997                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
3998                         break;
3999                 case OP_PMAXD:
4000                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4001                         break;
4002
4003                 case OP_PAVGB_UN:
4004                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4005                         break;
4006                 case OP_PAVGW_UN:
4007                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4008                         break;
4009
4010                 case OP_PMINB_UN:
4011                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4012                         break;
4013                 case OP_PMINW_UN:
4014                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4015                         break;
4016                 case OP_PMIND_UN:
4017                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4018                         break;
4019
4020                 case OP_PMINB:
4021                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4022                         break;
4023                 case OP_PMINW:
4024                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4025                         break;
4026                 case OP_PMIND:
4027                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4028                         break;
4029
4030                 case OP_PCMPEQB:
4031                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4032                         break;
4033                 case OP_PCMPEQW:
4034                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4035                         break;
4036                 case OP_PCMPEQD:
4037                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4038                         break;
4039                 case OP_PCMPEQQ:
4040                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4041                         break;
4042
4043                 case OP_PCMPGTB:
4044                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4045                         break;
4046                 case OP_PCMPGTW:
4047                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4048                         break;
4049                 case OP_PCMPGTD:
4050                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4051                         break;
4052                 case OP_PCMPGTQ:
4053                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4054                         break;
4055
4056                 case OP_PSUM_ABS_DIFF:
4057                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4058                         break;
4059
4060                 case OP_UNPACK_LOWB:
4061                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4062                         break;
4063                 case OP_UNPACK_LOWW:
4064                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4065                         break;
4066                 case OP_UNPACK_LOWD:
4067                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4068                         break;
4069                 case OP_UNPACK_LOWQ:
4070                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4071                         break;
4072                 case OP_UNPACK_LOWPS:
4073                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4074                         break;
4075                 case OP_UNPACK_LOWPD:
4076                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4077                         break;
4078
4079                 case OP_UNPACK_HIGHB:
4080                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4081                         break;
4082                 case OP_UNPACK_HIGHW:
4083                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4084                         break;
4085                 case OP_UNPACK_HIGHD:
4086                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4087                         break;
4088                 case OP_UNPACK_HIGHQ:
4089                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4090                         break;
4091                 case OP_UNPACK_HIGHPS:
4092                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4093                         break;
4094                 case OP_UNPACK_HIGHPD:
4095                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4096                         break;
4097
4098                 case OP_PACKW:
4099                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4100                         break;
4101                 case OP_PACKD:
4102                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4103                         break;
4104                 case OP_PACKW_UN:
4105                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4106                         break;
4107                 case OP_PACKD_UN:
4108                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4109                         break;
4110
4111                 case OP_PADDB_SAT_UN:
4112                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4113                         break;
4114                 case OP_PSUBB_SAT_UN:
4115                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4116                         break;
4117                 case OP_PADDW_SAT_UN:
4118                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4119                         break;
4120                 case OP_PSUBW_SAT_UN:
4121                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4122                         break;
4123
4124                 case OP_PADDB_SAT:
4125                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4126                         break;
4127                 case OP_PSUBB_SAT:
4128                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4129                         break;
4130                 case OP_PADDW_SAT:
4131                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4132                         break;
4133                 case OP_PSUBW_SAT:
4134                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4135                         break;
4136                         
4137                 case OP_PMULW:
4138                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4139                         break;
4140                 case OP_PMULD:
4141                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4142                         break;
4143                 case OP_PMULQ:
4144                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4145                         break;
4146                 case OP_PMULW_HIGH_UN:
4147                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4148                         break;
4149                 case OP_PMULW_HIGH:
4150                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4151                         break;
4152
4153                 case OP_PSHRW:
4154                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4155                         break;
4156                 case OP_PSHRW_REG:
4157                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4158                         break;
4159
4160                 case OP_PSARW:
4161                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4162                         break;
4163                 case OP_PSARW_REG:
4164                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4165                         break;
4166
4167                 case OP_PSHLW:
4168                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4169                         break;
4170                 case OP_PSHLW_REG:
4171                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4172                         break;
4173
4174                 case OP_PSHRD:
4175                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4176                         break;
4177                 case OP_PSHRD_REG:
4178                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4179                         break;
4180
4181                 case OP_PSARD:
4182                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4183                         break;
4184                 case OP_PSARD_REG:
4185                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4186                         break;
4187
4188                 case OP_PSHLD:
4189                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4190                         break;
4191                 case OP_PSHLD_REG:
4192                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4193                         break;
4194
4195                 case OP_PSHRQ:
4196                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4197                         break;
4198                 case OP_PSHRQ_REG:
4199                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4200                         break;
4201
4202                 case OP_PSHLQ:
4203                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4204                         break;
4205                 case OP_PSHLQ_REG:
4206                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4207                         break;          
4208                         
4209                 case OP_ICONV_TO_X:
4210                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4211                         break;
4212                 case OP_EXTRACT_I4:
4213                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4214                         break;
4215                 case OP_EXTRACT_I1:
4216                 case OP_EXTRACT_U1:
4217                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4218                         if (ins->inst_c0)
4219                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4220                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4221                         break;
4222                 case OP_EXTRACT_I2:
4223                 case OP_EXTRACT_U2:
4224                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4225                         if (ins->inst_c0)
4226                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4227                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4228                         break;
4229                 case OP_EXTRACT_R8:
4230                         if (ins->inst_c0)
4231                                 x86_sse_alu_pd_membase_reg (code, X86_SSE_MOVHPD_MEMBASE_REG, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1);
4232                         else
4233                                 x86_sse_alu_sd_membase_reg (code, X86_SSE_MOVSD_MEMBASE_REG, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1);
4234                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4235                         break;
4236
4237                 case OP_INSERT_I2:
4238                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4239                         break;
4240                 case OP_EXTRACTX_U2:
4241                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4242                         break;
4243                 case OP_INSERTX_U1_SLOW:
4244                         /*sreg1 is the extracted ireg (scratch)
4245                         /sreg2 is the to be inserted ireg (scratch)
4246                         /dreg is the xreg to receive the value*/
4247
4248                         /*clear the bits from the extracted word*/
4249                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4250                         /*shift the value to insert if needed*/
4251                         if (ins->inst_c0 & 1)
4252                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4253                         /*join them together*/
4254                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4255                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4256                         break;
4257                 case OP_INSERTX_I4_SLOW:
4258                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4259                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4260                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4261                         break;
4262
4263                 case OP_INSERTX_R4_SLOW:
4264                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4265                         /*TODO if inst_c0 == 0 use movss*/
4266                         x86_sse_alu_pd_reg_membase_imm (code, X86_SSE_PINSRW, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset + 0, ins->inst_c0 * 2);
4267                         x86_sse_alu_pd_reg_membase_imm (code, X86_SSE_PINSRW, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset + 2, ins->inst_c0 * 2 + 1);
4268                         break;
4269                 case OP_INSERTX_R8_SLOW:
4270                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4271                         if (ins->inst_c0)
4272                                 x86_sse_alu_pd_reg_membase (code, X86_SSE_MOVHPD_REG_MEMBASE, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4273                         else
4274                                 x86_sse_alu_pd_reg_membase (code, X86_SSE_MOVSD_REG_MEMBASE, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4275                         break;
4276
4277                 case OP_STOREX_MEMBASE_REG:
4278                 case OP_STOREX_MEMBASE:
4279                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4280                         break;
4281                 case OP_LOADX_MEMBASE:
4282                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4283                         break;
4284                 case OP_LOADX_ALIGNED_MEMBASE:
4285                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4286                         break;
4287                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4288                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4289                         break;
4290                 case OP_STOREX_NTA_MEMBASE_REG:
4291                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4292                         break;
4293                 case OP_PREFETCH_MEMBASE:
4294                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4295
4296                         break;
4297                 case OP_XMOVE:
4298                         /*FIXME the peephole pass should have killed this*/
4299                         if (ins->dreg != ins->sreg1)
4300                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4301                         break;          
4302                 case OP_XZERO:
4303                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4304                         break;
4305                 case OP_ICONV_TO_R8_RAW:
4306                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4307                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4308                         break;
4309
4310                 case OP_FCONV_TO_R8_X:
4311                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4312                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4313                         break;
4314
4315                 case OP_XCONV_R8_TO_I4:
4316                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4317                         switch (ins->backend.source_opcode) {
4318                         case OP_FCONV_TO_I1:
4319                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4320                                 break;
4321                         case OP_FCONV_TO_U1:
4322                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4323                                 break;
4324                         case OP_FCONV_TO_I2:
4325                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4326                                 break;
4327                         case OP_FCONV_TO_U2:
4328                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4329                                 break;
4330                         }                       
4331                         break;
4332
4333                 case OP_EXPAND_I1:
4334                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4335                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4336                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4337                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4338                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4339                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4340                         break;
4341                 case OP_EXPAND_I2:
4342                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4343                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4344                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4345                         break;
4346                 case OP_EXPAND_I4:
4347                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4348                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4349                         break;
4350                 case OP_EXPAND_R4:
4351                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4352                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4353                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4354                         break;
4355                 case OP_EXPAND_R8:
4356                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4357                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4358                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4359                         break;
4360 #endif
4361                 case OP_LIVERANGE_START: {
4362                         if (cfg->verbose_level > 1)
4363                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4364                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4365                         break;
4366                 }
4367                 case OP_LIVERANGE_END: {
4368                         if (cfg->verbose_level > 1)
4369                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4370                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4371                         break;
4372                 }
4373                 default:
4374                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
4375                         g_assert_not_reached ();
4376                 }
4377
4378                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
4379                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4380                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4381                         g_assert_not_reached ();
4382                 }
4383                
4384                 cpos += max_len;
4385         }
4386
4387         cfg->code_len = code - cfg->native_code;
4388 }
4389
4390 #endif /* DISABLE_JIT */
4391
4392 void
4393 mono_arch_register_lowlevel_calls (void)
4394 {
4395 }
4396
4397 void
4398 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4399 {
4400         MonoJumpInfo *patch_info;
4401         gboolean compile_aot = !run_cctors;
4402
4403         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4404                 unsigned char *ip = patch_info->ip.i + code;
4405                 const unsigned char *target;
4406
4407                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4408
4409                 if (compile_aot) {
4410                         switch (patch_info->type) {
4411                         case MONO_PATCH_INFO_BB:
4412                         case MONO_PATCH_INFO_LABEL:
4413                                 break;
4414                         default:
4415                                 /* No need to patch these */
4416                                 continue;
4417                         }
4418                 }
4419
4420                 switch (patch_info->type) {
4421                 case MONO_PATCH_INFO_IP:
4422                         *((gconstpointer *)(ip)) = target;
4423                         break;
4424                 case MONO_PATCH_INFO_CLASS_INIT: {
4425                         guint8 *code = ip;
4426                         /* Might already been changed to a nop */
4427                         x86_call_code (code, 0);
4428                         x86_patch (ip, target);
4429                         break;
4430                 }
4431                 case MONO_PATCH_INFO_ABS:
4432                 case MONO_PATCH_INFO_METHOD:
4433                 case MONO_PATCH_INFO_METHOD_JUMP:
4434                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4435                 case MONO_PATCH_INFO_BB:
4436                 case MONO_PATCH_INFO_LABEL:
4437                 case MONO_PATCH_INFO_RGCTX_FETCH:
4438                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
4439                 case MONO_PATCH_INFO_MONITOR_ENTER:
4440                 case MONO_PATCH_INFO_MONITOR_EXIT:
4441                         x86_patch (ip, target);
4442                         break;
4443                 case MONO_PATCH_INFO_NONE:
4444                         break;
4445                 default: {
4446                         guint32 offset = mono_arch_get_patch_offset (ip);
4447                         *((gconstpointer *)(ip + offset)) = target;
4448                         break;
4449                 }
4450                 }
4451         }
4452 }
4453
4454 guint8 *
4455 mono_arch_emit_prolog (MonoCompile *cfg)
4456 {
4457         MonoMethod *method = cfg->method;
4458         MonoBasicBlock *bb;
4459         MonoMethodSignature *sig;
4460         MonoInst *inst;
4461         int alloc_size, pos, max_offset, i, cfa_offset;
4462         guint8 *code;
4463         gboolean need_stack_frame;
4464
4465         cfg->code_size = MAX (mono_method_get_header (method)->code_size * 4, 10240);
4466
4467         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4468                 cfg->code_size += 512;
4469
4470         code = cfg->native_code = g_malloc (cfg->code_size);
4471
4472         /* Offset between RSP and the CFA */
4473         cfa_offset = 0;
4474
4475         // CFA = sp + 4
4476         cfa_offset = sizeof (gpointer);
4477         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
4478         // IP saved at CFA - 4
4479         /* There is no IP reg on x86 */
4480         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
4481
4482         need_stack_frame = needs_stack_frame (cfg);
4483
4484         if (need_stack_frame) {
4485                 x86_push_reg (code, X86_EBP);
4486                 cfa_offset += sizeof (gpointer);
4487                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4488                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
4489                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
4490                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
4491         }
4492
4493         alloc_size = cfg->stack_offset;
4494         pos = 0;
4495
4496         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4497                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
4498                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
4499                         guint8 *buf, *no_domain_branch;
4500
4501                         code = mono_x86_emit_tls_get (code, X86_EAX, appdomain_tls_offset);
4502                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
4503                         no_domain_branch = code;
4504                         x86_branch8 (code, X86_CC_NE, 0, 0);
4505                         code = mono_x86_emit_tls_get ( code, X86_EAX, lmf_tls_offset);
4506                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
4507                         buf = code;
4508                         x86_branch8 (code, X86_CC_NE, 0, 0);
4509                         x86_patch (no_domain_branch, code);
4510                         x86_push_imm (code, cfg->domain);
4511                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4512                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4513                         x86_patch (buf, code);
4514 #ifdef PLATFORM_WIN32
4515                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4516                         /* FIXME: Add a separate key for LMF to avoid this */
4517                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4518 #endif
4519                 }
4520                 else {
4521                         g_assert (!cfg->compile_aot);
4522                         x86_push_imm (code, cfg->domain);
4523                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4524                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4525                 }
4526         }
4527
4528         if (method->save_lmf) {
4529                 pos += sizeof (MonoLMF);
4530
4531                 if (cfg->compile_aot)
4532                         cfg->disable_aot = TRUE;
4533
4534                 /* save the current IP */
4535                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4536                 x86_push_imm_template (code);
4537                 cfa_offset += sizeof (gpointer);
4538
4539                 /* save all caller saved regs */
4540                 x86_push_reg (code, X86_EBP);
4541                 cfa_offset += sizeof (gpointer);
4542                 x86_push_reg (code, X86_ESI);
4543                 cfa_offset += sizeof (gpointer);
4544                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4545                 x86_push_reg (code, X86_EDI);
4546                 cfa_offset += sizeof (gpointer);
4547                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4548                 x86_push_reg (code, X86_EBX);
4549                 cfa_offset += sizeof (gpointer);
4550                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4551
4552                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4553                         /*
4554                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4555                          * through the mono_lmf_addr TLS variable.
4556                          */
4557                         /* %eax = previous_lmf */
4558                         x86_prefix (code, X86_GS_PREFIX);
4559                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
4560                         /* skip esp + method_info + lmf */
4561                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
4562                         /* push previous_lmf */
4563                         x86_push_reg (code, X86_EAX);
4564                         /* new lmf = ESP */
4565                         x86_prefix (code, X86_GS_PREFIX);
4566                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
4567                 } else {
4568                         /* get the address of lmf for the current thread */
4569                         /* 
4570                          * This is performance critical so we try to use some tricks to make
4571                          * it fast.
4572                          */                                                                        
4573
4574                         if (lmf_addr_tls_offset != -1) {
4575                                 /* Load lmf quicky using the GS register */
4576                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
4577 #ifdef PLATFORM_WIN32
4578                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4579                                 /* FIXME: Add a separate key for LMF to avoid this */
4580                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4581 #endif
4582                         } else {
4583                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
4584                         }
4585
4586                         /* Skip esp + method info */
4587                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
4588
4589                         /* push lmf */
4590                         x86_push_reg (code, X86_EAX); 
4591                         /* push *lfm (previous_lmf) */
4592                         x86_push_membase (code, X86_EAX, 0);
4593                         /* *(lmf) = ESP */
4594                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
4595                 }
4596         } else {
4597
4598                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4599                         x86_push_reg (code, X86_EBX);
4600                         pos += 4;
4601                         cfa_offset += sizeof (gpointer);
4602                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4603                 }
4604
4605                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4606                         x86_push_reg (code, X86_EDI);
4607                         pos += 4;
4608                         cfa_offset += sizeof (gpointer);
4609                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4610                 }
4611
4612                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4613                         x86_push_reg (code, X86_ESI);
4614                         pos += 4;
4615                         cfa_offset += sizeof (gpointer);
4616                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4617                 }
4618         }
4619
4620         alloc_size -= pos;
4621
4622         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
4623         if (mono_do_x86_stack_align && need_stack_frame) {
4624                 int tot = alloc_size + pos + 4; /* ret ip */
4625                 if (need_stack_frame)
4626                         tot += 4; /* ebp */
4627                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
4628                 if (tot)
4629                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
4630         }
4631
4632         if (alloc_size) {
4633                 /* See mono_emit_stack_alloc */
4634 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4635                 guint32 remaining_size = alloc_size;
4636                 while (remaining_size >= 0x1000) {
4637                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
4638                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
4639                         remaining_size -= 0x1000;
4640                 }
4641                 if (remaining_size)
4642                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
4643 #else
4644                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4645 #endif
4646
4647                 g_assert (need_stack_frame);
4648         }
4649
4650         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
4651                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
4652                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
4653         }
4654
4655 #if DEBUG_STACK_ALIGNMENT
4656         /* check the stack is aligned */
4657         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
4658                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
4659                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
4660                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4661                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4662                 x86_breakpoint (code);
4663         }
4664 #endif
4665
4666         /* compute max_offset in order to use short forward jumps */
4667         max_offset = 0;
4668         if (cfg->opt & MONO_OPT_BRANCH) {
4669                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4670                         MonoInst *ins;
4671                         bb->max_offset = max_offset;
4672
4673                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4674                                 max_offset += 6;
4675                         /* max alignment for loops */
4676                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4677                                 max_offset += LOOP_ALIGNMENT;
4678
4679                         MONO_BB_FOR_EACH_INS (bb, ins) {
4680                                 if (ins->opcode == OP_LABEL)
4681                                         ins->inst_c1 = max_offset;
4682                                 
4683                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4684                         }
4685                 }
4686         }
4687
4688         /* store runtime generic context */
4689         if (cfg->rgctx_var) {
4690                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4691
4692                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4693         }
4694
4695         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4696                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4697
4698         /* load arguments allocated to register from the stack */
4699         sig = mono_method_signature (method);
4700         pos = 0;
4701
4702         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4703                 inst = cfg->args [pos];
4704                 if (inst->opcode == OP_REGVAR) {
4705                         g_assert (need_stack_frame);
4706                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
4707                         if (cfg->verbose_level > 2)
4708                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4709                 }
4710                 pos++;
4711         }
4712
4713         cfg->code_len = code - cfg->native_code;
4714
4715         g_assert (cfg->code_len < cfg->code_size);
4716
4717         return code;
4718 }
4719
4720 void
4721 mono_arch_emit_epilog (MonoCompile *cfg)
4722 {
4723         MonoMethod *method = cfg->method;
4724         MonoMethodSignature *sig = mono_method_signature (method);
4725         int quad, pos;
4726         guint32 stack_to_pop;
4727         guint8 *code;
4728         int max_epilog_size = 16;
4729         CallInfo *cinfo;
4730         gboolean need_stack_frame = needs_stack_frame (cfg);
4731
4732         if (cfg->method->save_lmf)
4733                 max_epilog_size += 128;
4734
4735         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4736                 cfg->code_size *= 2;
4737                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4738                 mono_jit_stats.code_reallocs++;
4739         }
4740
4741         code = cfg->native_code + cfg->code_len;
4742
4743         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4744                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4745
4746         /* the code restoring the registers must be kept in sync with OP_JMP */
4747         pos = 0;
4748         
4749         if (method->save_lmf) {
4750                 gint32 prev_lmf_reg;
4751                 gint32 lmf_offset = -sizeof (MonoLMF);
4752
4753                 /* check if we need to restore protection of the stack after a stack overflow */
4754                 if (mono_get_jit_tls_offset () != -1) {
4755                         guint8 *patch;
4756                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
4757                         /* we load the value in a separate instruction: this mechanism may be
4758                          * used later as a safer way to do thread interruption
4759                          */
4760                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
4761                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4762                         patch = code;
4763                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
4764                         /* note that the call trampoline will preserve eax/edx */
4765                         x86_call_reg (code, X86_ECX);
4766                         x86_patch (patch, code);
4767                 } else {
4768                         /* FIXME: maybe save the jit tls in the prolog */
4769                 }
4770                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4771                         /*
4772                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4773                          * through the mono_lmf_addr TLS variable.
4774                          */
4775                         /* reg = previous_lmf */
4776                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4777
4778                         /* lmf = previous_lmf */
4779                         x86_prefix (code, X86_GS_PREFIX);
4780                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
4781                 } else {
4782                         /* Find a spare register */
4783                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
4784                         case MONO_TYPE_I8:
4785                         case MONO_TYPE_U8:
4786                                 prev_lmf_reg = X86_EDI;
4787                                 cfg->used_int_regs |= (1 << X86_EDI);
4788                                 break;
4789                         default:
4790                                 prev_lmf_reg = X86_EDX;
4791                                 break;
4792                         }
4793
4794                         /* reg = previous_lmf */
4795                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4796
4797                         /* ecx = lmf */
4798                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
4799
4800                         /* *(lmf) = previous_lmf */
4801                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
4802                 }
4803
4804                 /* restore caller saved regs */
4805                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4806                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
4807                 }
4808
4809                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4810                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
4811                 }
4812                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4813                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
4814                 }
4815
4816                 /* EBP is restored by LEAVE */
4817         } else {
4818                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4819                         pos -= 4;
4820                 }
4821                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4822                         pos -= 4;
4823                 }
4824                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4825                         pos -= 4;
4826                 }
4827
4828                 if (pos) {
4829                         g_assert (need_stack_frame);
4830                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
4831                 }
4832
4833                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4834                         x86_pop_reg (code, X86_ESI);
4835                 }
4836                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4837                         x86_pop_reg (code, X86_EDI);
4838                 }
4839                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4840                         x86_pop_reg (code, X86_EBX);
4841                 }
4842         }
4843
4844         /* Load returned vtypes into registers if needed */
4845         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
4846         if (cinfo->ret.storage == ArgValuetypeInReg) {
4847                 for (quad = 0; quad < 2; quad ++) {
4848                         switch (cinfo->ret.pair_storage [quad]) {
4849                         case ArgInIReg:
4850                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
4851                                 break;
4852                         case ArgOnFloatFpStack:
4853                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
4854                                 break;
4855                         case ArgOnDoubleFpStack:
4856                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
4857                                 break;
4858                         case ArgNone:
4859                                 break;
4860                         default:
4861                                 g_assert_not_reached ();
4862                         }
4863                 }
4864         }
4865
4866         if (need_stack_frame)
4867                 x86_leave (code);
4868
4869         if (CALLCONV_IS_STDCALL (sig)) {
4870                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
4871
4872                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
4873         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
4874                 stack_to_pop = 4;
4875         else
4876                 stack_to_pop = 0;
4877
4878         if (stack_to_pop) {
4879                 g_assert (need_stack_frame);
4880                 x86_ret_imm (code, stack_to_pop);
4881         } else {
4882                 x86_ret (code);
4883         }
4884
4885         cfg->code_len = code - cfg->native_code;
4886
4887         g_assert (cfg->code_len < cfg->code_size);
4888 }
4889
4890 void
4891 mono_arch_emit_exceptions (MonoCompile *cfg)
4892 {
4893         MonoJumpInfo *patch_info;
4894         int nthrows, i;
4895         guint8 *code;
4896         MonoClass *exc_classes [16];
4897         guint8 *exc_throw_start [16], *exc_throw_end [16];
4898         guint32 code_size;
4899         int exc_count = 0;
4900
4901         /* Compute needed space */
4902         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4903                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4904                         exc_count++;
4905         }
4906
4907         /* 
4908          * make sure we have enough space for exceptions
4909          * 16 is the size of two push_imm instructions and a call
4910          */
4911         if (cfg->compile_aot)
4912                 code_size = exc_count * 32;
4913         else
4914                 code_size = exc_count * 16;
4915
4916         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4917                 cfg->code_size *= 2;
4918                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4919                 mono_jit_stats.code_reallocs++;
4920         }
4921
4922         code = cfg->native_code + cfg->code_len;
4923
4924         nthrows = 0;
4925         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4926                 switch (patch_info->type) {
4927                 case MONO_PATCH_INFO_EXC: {
4928                         MonoClass *exc_class;
4929                         guint8 *buf, *buf2;
4930                         guint32 throw_ip;
4931
4932                         x86_patch (patch_info->ip.i + cfg->native_code, code);
4933
4934                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4935                         g_assert (exc_class);
4936                         throw_ip = patch_info->ip.i;
4937
4938                         /* Find a throw sequence for the same exception class */
4939                         for (i = 0; i < nthrows; ++i)
4940                                 if (exc_classes [i] == exc_class)
4941                                         break;
4942                         if (i < nthrows) {
4943                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
4944                                 x86_jump_code (code, exc_throw_start [i]);
4945                                 patch_info->type = MONO_PATCH_INFO_NONE;
4946                         }
4947                         else {
4948                                 guint32 size;
4949
4950                                 /* Compute size of code following the push <OFFSET> */
4951                                 size = 5 + 5;
4952
4953                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
4954
4955                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
4956                                         /* Use the shorter form */
4957                                         buf = buf2 = code;
4958                                         x86_push_imm (code, 0);
4959                                 }
4960                                 else {
4961                                         buf = code;
4962                                         x86_push_imm (code, 0xf0f0f0f0);
4963                                         buf2 = code;
4964                                 }
4965
4966                                 if (nthrows < 16) {
4967                                         exc_classes [nthrows] = exc_class;
4968                                         exc_throw_start [nthrows] = code;
4969                                 }
4970
4971                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
4972                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4973                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4974                                 patch_info->ip.i = code - cfg->native_code;
4975                                 x86_call_code (code, 0);
4976                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
4977                                 while (buf < buf2)
4978                                         x86_nop (buf);
4979
4980                                 if (nthrows < 16) {
4981                                         exc_throw_end [nthrows] = code;
4982                                         nthrows ++;
4983                                 }
4984                         }
4985                         break;
4986                 }
4987                 default:
4988                         /* do nothing */
4989                         break;
4990                 }
4991         }
4992
4993         cfg->code_len = code - cfg->native_code;
4994
4995         g_assert (cfg->code_len < cfg->code_size);
4996 }
4997
4998 void
4999 mono_arch_flush_icache (guint8 *code, gint size)
5000 {
5001         /* not needed */
5002 }
5003
5004 void
5005 mono_arch_flush_register_windows (void)
5006 {
5007 }
5008
5009 gboolean 
5010 mono_arch_is_inst_imm (gint64 imm)
5011 {
5012         return TRUE;
5013 }
5014
5015 /*
5016  * Support for fast access to the thread-local lmf structure using the GS
5017  * segment register on NPTL + kernel 2.6.x.
5018  */
5019
5020 static gboolean tls_offset_inited = FALSE;
5021
5022 void
5023 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5024 {
5025         if (!tls_offset_inited) {
5026                 if (!getenv ("MONO_NO_TLS")) {
5027 #ifdef PLATFORM_WIN32
5028                         /* 
5029                          * We need to init this multiple times, since when we are first called, the key might not
5030                          * be initialized yet.
5031                          */
5032                         appdomain_tls_offset = mono_domain_get_tls_key ();
5033                         lmf_tls_offset = mono_get_jit_tls_key ();
5034
5035                         /* Only 64 tls entries can be accessed using inline code */
5036                         if (appdomain_tls_offset >= 64)
5037                                 appdomain_tls_offset = -1;
5038                         if (lmf_tls_offset >= 64)
5039                                 lmf_tls_offset = -1;
5040 #else
5041 #if MONO_XEN_OPT
5042                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5043 #endif
5044                         tls_offset_inited = TRUE;
5045                         appdomain_tls_offset = mono_domain_get_tls_offset ();
5046                         lmf_tls_offset = mono_get_lmf_tls_offset ();
5047                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5048 #endif
5049                 }
5050         }               
5051 }
5052
5053 void
5054 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5055 {
5056 }
5057
5058 #ifdef MONO_ARCH_HAVE_IMT
5059
5060 // Linear handler, the bsearch head compare is shorter
5061 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5062 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5063 //        x86_patch(ins,target)
5064 //[1 + 5] x86_jump_mem(inst,mem)
5065
5066 #define CMP_SIZE 6
5067 #define BR_SMALL_SIZE 2
5068 #define BR_LARGE_SIZE 5
5069 #define JUMP_IMM_SIZE 6
5070 #define ENABLE_WRONG_METHOD_CHECK 0
5071
5072 static int
5073 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5074 {
5075         int i, distance = 0;
5076         for (i = start; i < target; ++i)
5077                 distance += imt_entries [i]->chunk_size;
5078         return distance;
5079 }
5080
5081 /*
5082  * LOCKING: called with the domain lock held
5083  */
5084 gpointer
5085 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5086         gpointer fail_tramp)
5087 {
5088         int i;
5089         int size = 0;
5090         guint8 *code, *start;
5091
5092         for (i = 0; i < count; ++i) {
5093                 MonoIMTCheckItem *item = imt_entries [i];
5094                 if (item->is_equals) {
5095                         if (item->check_target_idx) {
5096                                 if (!item->compare_done)
5097                                         item->chunk_size += CMP_SIZE;
5098                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5099                         } else {
5100                                 if (fail_tramp) {
5101                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5102                                 } else {
5103                                         item->chunk_size += JUMP_IMM_SIZE;
5104 #if ENABLE_WRONG_METHOD_CHECK
5105                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5106 #endif
5107                                 }
5108                         }
5109                 } else {
5110                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5111                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5112                 }
5113                 size += item->chunk_size;
5114         }
5115         if (fail_tramp)
5116                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5117         else
5118                 code = mono_domain_code_reserve (domain, size);
5119         start = code;
5120         for (i = 0; i < count; ++i) {
5121                 MonoIMTCheckItem *item = imt_entries [i];
5122                 item->code_target = code;
5123                 if (item->is_equals) {
5124                         if (item->check_target_idx) {
5125                                 if (!item->compare_done)
5126                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5127                                 item->jmp_code = code;
5128                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5129                                 if (item->has_target_code)
5130                                         x86_jump_code (code, item->value.target_code);
5131                                 else
5132                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5133                         } else {
5134                                 if (fail_tramp) {
5135                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5136                                         item->jmp_code = code;
5137                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5138                                         if (item->has_target_code)
5139                                                 x86_jump_code (code, item->value.target_code);
5140                                         else
5141                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5142                                         x86_patch (item->jmp_code, code);
5143                                         x86_jump_code (code, fail_tramp);
5144                                         item->jmp_code = NULL;
5145                                 } else {
5146                                         /* enable the commented code to assert on wrong method */
5147 #if ENABLE_WRONG_METHOD_CHECK
5148                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5149                                         item->jmp_code = code;
5150                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5151 #endif
5152                                         if (item->has_target_code)
5153                                                 x86_jump_code (code, item->value.target_code);
5154                                         else
5155                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5156 #if ENABLE_WRONG_METHOD_CHECK
5157                                         x86_patch (item->jmp_code, code);
5158                                         x86_breakpoint (code);
5159                                         item->jmp_code = NULL;
5160 #endif
5161                                 }
5162                         }
5163                 } else {
5164                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5165                         item->jmp_code = code;
5166                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5167                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5168                         else
5169                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5170                 }
5171         }
5172         /* patch the branches to get to the target items */
5173         for (i = 0; i < count; ++i) {
5174                 MonoIMTCheckItem *item = imt_entries [i];
5175                 if (item->jmp_code) {
5176                         if (item->check_target_idx) {
5177                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5178                         }
5179                 }
5180         }
5181
5182         if (!fail_tramp)
5183                 mono_stats.imt_thunks_size += code - start;
5184         g_assert (code - start <= size);
5185         return start;
5186 }
5187
5188 MonoMethod*
5189 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5190 {
5191         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5192 }
5193
5194 MonoObject*
5195 mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5196 {
5197         MonoMethodSignature *sig = mono_method_signature (method);
5198         CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5199         int this_argument_offset;
5200         MonoObject *this_argument;
5201
5202         /* 
5203          * this is the offset of the this arg from esp as saved at the start of 
5204          * mono_arch_create_trampoline_code () in tramp-x86.c.
5205          */
5206         this_argument_offset = 5;
5207         if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
5208                 this_argument_offset++;
5209
5210         this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
5211
5212         g_free (cinfo);
5213         return this_argument;
5214 }
5215 #endif
5216
5217 MonoVTable*
5218 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5219 {
5220         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5221 }
5222
5223 MonoInst*
5224 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5225 {
5226         MonoInst *ins = NULL;
5227         int opcode = 0;
5228
5229         if (cmethod->klass == mono_defaults.math_class) {
5230                 if (strcmp (cmethod->name, "Sin") == 0) {
5231                         opcode = OP_SIN;
5232                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5233                         opcode = OP_COS;
5234                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5235                         opcode = OP_TAN;
5236                 } else if (strcmp (cmethod->name, "Atan") == 0) {
5237                         opcode = OP_ATAN;
5238                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5239                         opcode = OP_SQRT;
5240                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5241                         opcode = OP_ABS;
5242                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
5243                         opcode = OP_ROUND;
5244                 }
5245                 
5246                 if (opcode) {
5247                         MONO_INST_NEW (cfg, ins, opcode);
5248                         ins->type = STACK_R8;
5249                         ins->dreg = mono_alloc_freg (cfg);
5250                         ins->sreg1 = args [0]->dreg;
5251                         MONO_ADD_INS (cfg->cbb, ins);
5252                 }
5253
5254                 if (cfg->opt & MONO_OPT_CMOV) {
5255                         int opcode = 0;
5256
5257                         if (strcmp (cmethod->name, "Min") == 0) {
5258                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5259                                         opcode = OP_IMIN;
5260                         } else if (strcmp (cmethod->name, "Max") == 0) {
5261                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5262                                         opcode = OP_IMAX;
5263                         }               
5264
5265                         if (opcode) {
5266                                 MONO_INST_NEW (cfg, ins, opcode);
5267                                 ins->type = STACK_I4;
5268                                 ins->dreg = mono_alloc_ireg (cfg);
5269                                 ins->sreg1 = args [0]->dreg;
5270                                 ins->sreg2 = args [1]->dreg;
5271                                 MONO_ADD_INS (cfg->cbb, ins);
5272                         }
5273                 }
5274
5275 #if 0
5276                 /* OP_FREM is not IEEE compatible */
5277                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
5278                         MONO_INST_NEW (cfg, ins, OP_FREM);
5279                         ins->inst_i0 = args [0];
5280                         ins->inst_i1 = args [1];
5281                 }
5282 #endif
5283         }
5284
5285         return ins;
5286 }
5287
5288 gboolean
5289 mono_arch_print_tree (MonoInst *tree, int arity)
5290 {
5291         return 0;
5292 }
5293
5294 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5295 {
5296         MonoInst* ins;
5297
5298         return NULL;
5299
5300         if (appdomain_tls_offset == -1)
5301                 return NULL;
5302
5303         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5304         ins->inst_offset = appdomain_tls_offset;
5305         return ins;
5306 }
5307
5308 guint32
5309 mono_arch_get_patch_offset (guint8 *code)
5310 {
5311         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
5312                 return 2;
5313         else if ((code [0] == 0xba))
5314                 return 1;
5315         else if ((code [0] == 0x68))
5316                 /* push IMM */
5317                 return 1;
5318         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
5319                 /* push <OFFSET>(<REG>) */
5320                 return 2;
5321         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
5322                 /* call *<OFFSET>(<REG>) */
5323                 return 2;
5324         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
5325                 /* fldl <ADDR> */
5326                 return 2;
5327         else if ((code [0] == 0x58) && (code [1] == 0x05))
5328                 /* pop %eax; add <OFFSET>, %eax */
5329                 return 2;
5330         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
5331                 /* pop <REG>; add <OFFSET>, <REG> */
5332                 return 3;
5333         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
5334                 /* mov <REG>, imm */
5335                 return 1;
5336         else {
5337                 g_assert_not_reached ();
5338                 return -1;
5339         }
5340 }
5341
5342 /**
5343  * mono_breakpoint_clean_code:
5344  *
5345  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
5346  * breakpoints in the original code, they are removed in the copy.
5347  *
5348  * Returns TRUE if no sw breakpoint was present.
5349  */
5350 gboolean
5351 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
5352 {
5353         int i;
5354         gboolean can_write = TRUE;
5355         /*
5356          * If method_start is non-NULL we need to perform bound checks, since we access memory
5357          * at code - offset we could go before the start of the method and end up in a different
5358          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
5359          * instead.
5360          */
5361         if (!method_start || code - offset >= method_start) {
5362                 memcpy (buf, code - offset, size);
5363         } else {
5364                 int diff = code - method_start;
5365                 memset (buf, 0, size);
5366                 memcpy (buf + offset - diff, method_start, diff + size - offset);
5367         }
5368         code -= offset;
5369         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
5370                 int idx = mono_breakpoint_info_index [i];
5371                 guint8 *ptr;
5372                 if (idx < 1)
5373                         continue;
5374                 ptr = mono_breakpoint_info [idx].address;
5375                 if (ptr >= code && ptr < code + size) {
5376                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
5377                         can_write = FALSE;
5378                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
5379                         buf [ptr - code] = saved_byte;
5380                 }
5381         }
5382         return can_write;
5383 }
5384
5385 gpointer
5386 mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
5387 {
5388         guint8 buf [8];
5389         guint8 reg = 0;
5390         gint32 disp = 0;
5391
5392         mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
5393         code = buf + 8;
5394
5395         *displacement = 0;
5396
5397         code -= 6;
5398
5399         /* 
5400          * A given byte sequence can match more than case here, so we have to be
5401          * really careful about the ordering of the cases. Longer sequences
5402          * come first.
5403          * There are two types of calls:
5404          * - direct calls: 0xff address_byte 8/32 bits displacement
5405          * - indirect calls: nop nop nop <call>
5406          * The nops make sure we don't confuse the instruction preceeding an indirect
5407          * call with a direct call.
5408          */
5409         if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
5410                 reg = code [4] & 0x07;
5411                 disp = (signed char)code [5];
5412         } else if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
5413                 reg = code [1] & 0x07;
5414                 disp = *((gint32*)(code + 2));
5415         } else if ((code [1] == 0xe8)) {
5416                         return NULL;
5417         } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
5418                 /*
5419                  * This is a interface call
5420                  * 8b 40 30   mov    0x30(%eax),%eax
5421                  * ff 10      call   *(%eax)
5422                  */
5423                 disp = 0;
5424                 reg = code [5] & 0x07;
5425         }
5426         else
5427                 return NULL;
5428
5429         *displacement = disp;
5430         return (gpointer)regs [reg];
5431 }
5432
5433 gpointer
5434 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
5435                 mgreg_t *regs, guint8 *code)
5436 {
5437         guint32 esp = regs [X86_ESP];
5438         CallInfo *cinfo = NULL;
5439         gpointer res;
5440         int offset;
5441
5442         /* 
5443          * Avoid expensive calls to get_generic_context_from_code () + get_call_info 
5444          * if possible.
5445          */
5446         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5447                 if (!gsctx && code)
5448                         gsctx = mono_get_generic_context_from_code (code);
5449                 cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5450
5451                 offset = cinfo->args [0].offset;
5452         } else {
5453                 offset = 0;
5454         }
5455
5456         /*
5457          * The stack looks like:
5458          * <other args>
5459          * <this=delegate>
5460          * <possible vtype return address>
5461          * <return addr>
5462          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
5463          */
5464         res = (((MonoObject**)esp) [5 + (offset / 4)]);
5465         if (cinfo)
5466                 g_free (cinfo);
5467         return res;
5468 }
5469
5470 #define MAX_ARCH_DELEGATE_PARAMS 10
5471
5472 gpointer
5473 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5474 {
5475         guint8 *code, *start;
5476
5477         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
5478                 return NULL;
5479
5480         /* FIXME: Support more cases */
5481         if (MONO_TYPE_ISSTRUCT (sig->ret))
5482                 return NULL;
5483
5484         /*
5485          * The stack contains:
5486          * <delegate>
5487          * <return addr>
5488          */
5489
5490         if (has_target) {
5491                 static guint8* cached = NULL;
5492                 if (cached)
5493                         return cached;
5494                 
5495                 start = code = mono_global_codeman_reserve (64);
5496
5497                 /* Replace the this argument with the target */
5498                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
5499                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
5500                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
5501                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5502
5503                 g_assert ((code - start) < 64);
5504
5505                 mono_debug_add_delegate_trampoline (start, code - start);
5506
5507                 mono_memory_barrier ();
5508
5509                 cached = start;
5510         } else {
5511                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
5512                 int i = 0;
5513                 /* 8 for mov_reg and jump, plus 8 for each parameter */
5514                 int code_reserve = 8 + (sig->param_count * 8);
5515
5516                 for (i = 0; i < sig->param_count; ++i)
5517                         if (!mono_is_regsize_var (sig->params [i]))
5518                                 return NULL;
5519
5520                 code = cache [sig->param_count];
5521                 if (code)
5522                         return code;
5523
5524                 /*
5525                  * The stack contains:
5526                  * <args in reverse order>
5527                  * <delegate>
5528                  * <return addr>
5529                  *
5530                  * and we need:
5531                  * <args in reverse order>
5532                  * <return addr>
5533                  * 
5534                  * without unbalancing the stack.
5535                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
5536                  * and leaving original spot of first arg as placeholder in stack so
5537                  * when callee pops stack everything works.
5538                  */
5539
5540                 start = code = mono_global_codeman_reserve (code_reserve);
5541
5542                 /* store delegate for access to method_ptr */
5543                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
5544
5545                 /* move args up */
5546                 for (i = 0; i < sig->param_count; ++i) {
5547                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
5548                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
5549                 }
5550
5551                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5552
5553                 g_assert ((code - start) < code_reserve);
5554
5555                 mono_debug_add_delegate_trampoline (start, code - start);
5556
5557                 mono_memory_barrier ();
5558
5559                 cache [sig->param_count] = start;
5560         }
5561
5562         return start;
5563 }
5564
5565 gpointer
5566 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5567 {
5568         switch (reg) {
5569         case X86_EAX: return (gpointer)ctx->eax;
5570         case X86_EBX: return (gpointer)ctx->ebx;
5571         case X86_ECX: return (gpointer)ctx->ecx;
5572         case X86_EDX: return (gpointer)ctx->edx;
5573         case X86_ESP: return (gpointer)ctx->esp;
5574         case X86_EBP: return (gpointer)ctx->ebp;
5575         case X86_ESI: return (gpointer)ctx->esi;
5576         case X86_EDI: return (gpointer)ctx->edi;
5577         default: g_assert_not_reached ();
5578         }
5579 }
5580
5581 #ifdef MONO_ARCH_SIMD_INTRINSICS
5582
5583 static MonoInst*
5584 get_float_to_x_spill_area (MonoCompile *cfg)
5585 {
5586         if (!cfg->fconv_to_r8_x_var) {
5587                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5588                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
5589         }       
5590         return cfg->fconv_to_r8_x_var;
5591 }
5592
5593 /*
5594  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
5595  */
5596 void
5597 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5598 {
5599         MonoInst *fconv;
5600         int dreg, src_opcode;
5601
5602         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
5603                 return;
5604
5605         switch (src_opcode = ins->opcode) {
5606         case OP_FCONV_TO_I1:
5607         case OP_FCONV_TO_U1:
5608         case OP_FCONV_TO_I2:
5609         case OP_FCONV_TO_U2:
5610         case OP_FCONV_TO_I4:
5611         case OP_FCONV_TO_I:
5612                 break;
5613         default:
5614                 return;
5615         }
5616
5617         /* dreg is the IREG and sreg1 is the FREG */
5618         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
5619         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
5620         fconv->sreg1 = ins->sreg1;
5621         fconv->dreg = mono_alloc_ireg (cfg);
5622         fconv->type = STACK_VTYPE;
5623         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
5624
5625         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
5626
5627         dreg = ins->dreg;
5628         NULLIFY_INS (ins);
5629         ins->opcode = OP_XCONV_R8_TO_I4;
5630
5631         ins->klass = mono_defaults.int32_class;
5632         ins->sreg1 = fconv->dreg;
5633         ins->dreg = dreg;
5634         ins->type = STACK_I4;
5635         ins->backend.source_opcode = src_opcode;
5636 }
5637
5638 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
5639
5640 void
5641 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
5642 {
5643         MonoInst *ins;
5644         int vreg;
5645
5646         if (long_ins->opcode == OP_LNEG) {
5647                 ins = long_ins;
5648                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
5649                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
5650                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
5651                 NULLIFY_INS (ins);
5652                 return;
5653         }
5654
5655 #ifdef MONO_ARCH_SIMD_INTRINSICS
5656
5657         if (!(cfg->opt & MONO_OPT_SIMD))
5658                 return;
5659         
5660         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
5661         switch (long_ins->opcode) {
5662         case OP_EXTRACT_I8:
5663                 vreg = long_ins->sreg1;
5664         
5665                 if (long_ins->inst_c0) {
5666                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5667                         ins->klass = long_ins->klass;
5668                         ins->sreg1 = long_ins->sreg1;
5669                         ins->inst_c0 = 2;
5670                         ins->type = STACK_VTYPE;
5671                         ins->dreg = vreg = alloc_ireg (cfg);
5672                         MONO_ADD_INS (cfg->cbb, ins);
5673                 }
5674         
5675                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
5676                 ins->klass = mono_defaults.int32_class;
5677                 ins->sreg1 = vreg;
5678                 ins->type = STACK_I4;
5679                 ins->dreg = long_ins->dreg + 1;
5680                 MONO_ADD_INS (cfg->cbb, ins);
5681         
5682                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5683                 ins->klass = long_ins->klass;
5684                 ins->sreg1 = long_ins->sreg1;
5685                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
5686                 ins->type = STACK_VTYPE;
5687                 ins->dreg = vreg = alloc_ireg (cfg);
5688                 MONO_ADD_INS (cfg->cbb, ins);
5689         
5690                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
5691                 ins->klass = mono_defaults.int32_class;
5692                 ins->sreg1 = vreg;
5693                 ins->type = STACK_I4;
5694                 ins->dreg = long_ins->dreg + 2;
5695                 MONO_ADD_INS (cfg->cbb, ins);
5696         
5697                 long_ins->opcode = OP_NOP;
5698                 break;
5699         case OP_INSERTX_I8_SLOW:
5700                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5701                 ins->dreg = long_ins->dreg;
5702                 ins->sreg1 = long_ins->dreg;
5703                 ins->sreg2 = long_ins->sreg2 + 1;
5704                 ins->inst_c0 = long_ins->inst_c0 * 2;
5705                 MONO_ADD_INS (cfg->cbb, ins);
5706
5707                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5708                 ins->dreg = long_ins->dreg;
5709                 ins->sreg1 = long_ins->dreg;
5710                 ins->sreg2 = long_ins->sreg2 + 2;
5711                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
5712                 MONO_ADD_INS (cfg->cbb, ins);
5713
5714                 long_ins->opcode = OP_NOP;
5715                 break;
5716         case OP_EXPAND_I8:
5717                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
5718                 ins->dreg = long_ins->dreg;
5719                 ins->sreg1 = long_ins->sreg1 + 1;
5720                 ins->klass = long_ins->klass;
5721                 ins->type = STACK_VTYPE;
5722                 MONO_ADD_INS (cfg->cbb, ins);
5723
5724                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5725                 ins->dreg = long_ins->dreg;
5726                 ins->sreg1 = long_ins->dreg;
5727                 ins->sreg2 = long_ins->sreg1 + 2;
5728                 ins->inst_c0 = 1;
5729                 ins->klass = long_ins->klass;
5730                 ins->type = STACK_VTYPE;
5731                 MONO_ADD_INS (cfg->cbb, ins);
5732
5733                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5734                 ins->dreg = long_ins->dreg;
5735                 ins->sreg1 = long_ins->dreg;;
5736                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
5737                 ins->klass = long_ins->klass;
5738                 ins->type = STACK_VTYPE;
5739                 MONO_ADD_INS (cfg->cbb, ins);
5740
5741                 long_ins->opcode = OP_NOP;
5742                 break;
5743         }
5744 #endif /* MONO_ARCH_SIMD_INTRINSICS */
5745 }
5746
5747 #if __APPLE__
5748 #define DBG_SIGNAL SIGBUS
5749 #else
5750 #define DBG_SIGNAL SIGSEGV
5751 #endif
5752
5753 /*
5754  * mono_arch_set_breakpoint:
5755  *
5756  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
5757  * The location should contain code emitted by OP_SEQ_POINT.
5758  */
5759 void
5760 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5761 {
5762         guint8 *code = ip;
5763
5764         /* 
5765          * In production, we will use int3 (has to fix the size in the md 
5766          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
5767          * instead.
5768          */
5769         g_assert (code [0] == 0x90);
5770         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
5771 }
5772
5773 /*
5774  * mono_arch_clear_breakpoint:
5775  *
5776  *   Clear the breakpoint at IP.
5777  */
5778 void
5779 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5780 {
5781         guint8 *code = ip;
5782         int i;
5783
5784         for (i = 0; i < 6; ++i)
5785                 x86_nop (code);
5786 }
5787         
5788 /*
5789  * mono_arch_start_single_stepping:
5790  *
5791  *   Start single stepping.
5792  */
5793 void
5794 mono_arch_start_single_stepping (void)
5795 {
5796         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5797 }
5798         
5799 /*
5800  * mono_arch_stop_single_stepping:
5801  *
5802  *   Stop single stepping.
5803  */
5804 void
5805 mono_arch_stop_single_stepping (void)
5806 {
5807         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5808 }
5809
5810 /*
5811  * mono_arch_is_single_step_event:
5812  *
5813  *   Return whenever the machine state in SIGCTX corresponds to a single
5814  * step event.
5815  */
5816 gboolean
5817 mono_arch_is_single_step_event (siginfo_t *info, void *sigctx)
5818 {
5819         /* Sometimes the address is off by 4 */
5820         if (info->si_signo == DBG_SIGNAL && (info->si_addr >= ss_trigger_page && (guint8*)info->si_addr <= (guint8*)ss_trigger_page + 128))
5821                 return TRUE;
5822         else
5823                 return FALSE;
5824 }
5825
5826 gboolean
5827 mono_arch_is_breakpoint_event (siginfo_t *info, void *sigctx)
5828 {
5829         /* Sometimes the address is off by 4 */
5830         if (info->si_signo == DBG_SIGNAL && (info->si_addr >= bp_trigger_page && (guint8*)info->si_addr <= (guint8*)bp_trigger_page + 128))
5831                 return TRUE;
5832         else
5833                 return FALSE;
5834 }
5835
5836 /*
5837  * mono_arch_get_ip_for_breakpoint:
5838  *
5839  *   See mini-amd64.c for docs.
5840  */
5841 guint8*
5842 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
5843 {
5844         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5845
5846         return ip;
5847 }
5848
5849 #define BREAKPOINT_SIZE 6
5850
5851 /*
5852  * mono_arch_get_ip_for_single_step:
5853  *
5854  *   See mini-amd64.c for docs.
5855  */
5856 guint8*
5857 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
5858 {
5859         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5860
5861         /* Size of x86_alu_reg_imm */
5862         ip += 6;
5863
5864         return ip;
5865 }
5866
5867 /*
5868  * mono_arch_skip_breakpoint:
5869  *
5870  *   See mini-amd64.c for docs.
5871  */
5872 void
5873 mono_arch_skip_breakpoint (MonoContext *ctx)
5874 {
5875         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
5876 }
5877
5878 /*
5879  * mono_arch_skip_single_step:
5880  *
5881  *   See mini-amd64.c for docs.
5882  */
5883 void
5884 mono_arch_skip_single_step (MonoContext *ctx)
5885 {
5886         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
5887 }
5888
5889 /*
5890  * mono_arch_get_seq_point_info:
5891  *
5892  *   See mini-amd64.c for docs.
5893  */
5894 gpointer
5895 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5896 {
5897         NOT_IMPLEMENTED;
5898         return NULL;
5899 }