New tests.
[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                         if (cfg->compile_aot)
2361                                 NOT_IMPLEMENTED;
2362
2363                         /* 
2364                          * Read from the single stepping trigger page. This will cause a
2365                          * SIGSEGV when single stepping is enabled.
2366                          * We do this _before_ the breakpoint, so single stepping after
2367                          * a breakpoint is hit will step to the next IL offset.
2368                          */
2369                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
2370                                 x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
2371
2372                         il_offset = ins->inst_imm;
2373
2374                         if (!cfg->seq_points)
2375                                 cfg->seq_points = g_ptr_array_new ();
2376                         g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
2377                         g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
2378                         /* 
2379                          * A placeholder for a possible breakpoint inserted by
2380                          * mono_arch_set_breakpoint ().
2381                          */
2382                         for (i = 0; i < 6; ++i)
2383                                 x86_nop (code);
2384                         break;
2385                 }
2386                 case OP_ADDCC:
2387                 case OP_IADDCC:
2388                 case OP_IADD:
2389                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2390                         break;
2391                 case OP_ADC:
2392                 case OP_IADC:
2393                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2394                         break;
2395                 case OP_ADDCC_IMM:
2396                 case OP_ADD_IMM:
2397                 case OP_IADD_IMM:
2398                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2399                         break;
2400                 case OP_ADC_IMM:
2401                 case OP_IADC_IMM:
2402                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2403                         break;
2404                 case OP_SUBCC:
2405                 case OP_ISUBCC:
2406                 case OP_ISUB:
2407                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2408                         break;
2409                 case OP_SBB:
2410                 case OP_ISBB:
2411                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2412                         break;
2413                 case OP_SUBCC_IMM:
2414                 case OP_SUB_IMM:
2415                 case OP_ISUB_IMM:
2416                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2417                         break;
2418                 case OP_SBB_IMM:
2419                 case OP_ISBB_IMM:
2420                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2421                         break;
2422                 case OP_IAND:
2423                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2424                         break;
2425                 case OP_AND_IMM:
2426                 case OP_IAND_IMM:
2427                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2428                         break;
2429                 case OP_IDIV:
2430                 case OP_IREM:
2431                         /* 
2432                          * The code is the same for div/rem, the allocator will allocate dreg
2433                          * to RAX/RDX as appropriate.
2434                          */
2435                         if (ins->sreg2 == X86_EDX) {
2436                                 /* cdq clobbers this */
2437                                 x86_push_reg (code, ins->sreg2);
2438                                 x86_cdq (code);
2439                                 x86_div_membase (code, X86_ESP, 0, TRUE);
2440                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2441                         } else {
2442                                 x86_cdq (code);
2443                                 x86_div_reg (code, ins->sreg2, TRUE);
2444                         }
2445                         break;
2446                 case OP_IDIV_UN:
2447                 case OP_IREM_UN:
2448                         if (ins->sreg2 == X86_EDX) {
2449                                 x86_push_reg (code, ins->sreg2);
2450                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2451                                 x86_div_membase (code, X86_ESP, 0, FALSE);
2452                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2453                         } else {
2454                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2455                                 x86_div_reg (code, ins->sreg2, FALSE);
2456                         }
2457                         break;
2458                 case OP_DIV_IMM:
2459                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2460                         x86_cdq (code);
2461                         x86_div_reg (code, ins->sreg2, TRUE);
2462                         break;
2463                 case OP_IREM_IMM: {
2464                         int power = mono_is_power_of_two (ins->inst_imm);
2465
2466                         g_assert (ins->sreg1 == X86_EAX);
2467                         g_assert (ins->dreg == X86_EAX);
2468                         g_assert (power >= 0);
2469
2470                         if (power == 1) {
2471                                 /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */
2472                                 x86_cdq (code);
2473                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
2474                                 /* 
2475                                  * If the divident is >= 0, this does not nothing. If it is positive, it
2476                                  * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1.
2477                                  */
2478                                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EDX);
2479                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2480                         } else if (power == 0) {
2481                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
2482                         } else {
2483                                 /* Based on gcc code */
2484
2485                                 /* Add compensation for negative dividents */
2486                                 x86_cdq (code);
2487                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 - power);
2488                                 x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EDX);
2489                                 /* Compute remainder */
2490                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 << power) - 1);
2491                                 /* Remove compensation */
2492                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2493                         }
2494                         break;
2495                 }
2496                 case OP_IOR:
2497                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2498                         break;
2499                 case OP_OR_IMM:
2500                 case OP_IOR_IMM:
2501                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2502                         break;
2503                 case OP_IXOR:
2504                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2505                         break;
2506                 case OP_XOR_IMM:
2507                 case OP_IXOR_IMM:
2508                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2509                         break;
2510                 case OP_ISHL:
2511                         g_assert (ins->sreg2 == X86_ECX);
2512                         x86_shift_reg (code, X86_SHL, ins->dreg);
2513                         break;
2514                 case OP_ISHR:
2515                         g_assert (ins->sreg2 == X86_ECX);
2516                         x86_shift_reg (code, X86_SAR, ins->dreg);
2517                         break;
2518                 case OP_SHR_IMM:
2519                 case OP_ISHR_IMM:
2520                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2521                         break;
2522                 case OP_SHR_UN_IMM:
2523                 case OP_ISHR_UN_IMM:
2524                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2525                         break;
2526                 case OP_ISHR_UN:
2527                         g_assert (ins->sreg2 == X86_ECX);
2528                         x86_shift_reg (code, X86_SHR, ins->dreg);
2529                         break;
2530                 case OP_SHL_IMM:
2531                 case OP_ISHL_IMM:
2532                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2533                         break;
2534                 case OP_LSHL: {
2535                         guint8 *jump_to_end;
2536
2537                         /* handle shifts below 32 bits */
2538                         x86_shld_reg (code, ins->backend.reg3, ins->sreg1);
2539                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2540
2541                         x86_test_reg_imm (code, X86_ECX, 32);
2542                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2543
2544                         /* handle shift over 32 bit */
2545                         x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2546                         x86_clear_reg (code, ins->sreg1);
2547                         
2548                         x86_patch (jump_to_end, code);
2549                         }
2550                         break;
2551                 case OP_LSHR: {
2552                         guint8 *jump_to_end;
2553
2554                         /* handle shifts below 32 bits */
2555                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2556                         x86_shift_reg (code, X86_SAR, ins->backend.reg3);
2557
2558                         x86_test_reg_imm (code, X86_ECX, 32);
2559                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2560
2561                         /* handle shifts over 31 bits */
2562                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2563                         x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31);
2564                         
2565                         x86_patch (jump_to_end, code);
2566                         }
2567                         break;
2568                 case OP_LSHR_UN: {
2569                         guint8 *jump_to_end;
2570
2571                         /* handle shifts below 32 bits */
2572                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2573                         x86_shift_reg (code, X86_SHR, ins->backend.reg3);
2574
2575                         x86_test_reg_imm (code, X86_ECX, 32);
2576                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2577
2578                         /* handle shifts over 31 bits */
2579                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2580                         x86_clear_reg (code, ins->backend.reg3);
2581                         
2582                         x86_patch (jump_to_end, code);
2583                         }
2584                         break;
2585                 case OP_LSHL_IMM:
2586                         if (ins->inst_imm >= 32) {
2587                                 x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2588                                 x86_clear_reg (code, ins->sreg1);
2589                                 x86_shift_reg_imm (code, X86_SHL, ins->backend.reg3, ins->inst_imm - 32);
2590                         } else {
2591                                 x86_shld_reg_imm (code, ins->backend.reg3, ins->sreg1, ins->inst_imm);
2592                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
2593                         }
2594                         break;
2595                 case OP_LSHR_IMM:
2596                         if (ins->inst_imm >= 32) {
2597                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3,  4);
2598                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 0x1f);
2599                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
2600                         } else {
2601                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2602                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, ins->inst_imm);
2603                         }
2604                         break;
2605                 case OP_LSHR_UN_IMM:
2606                         if (ins->inst_imm >= 32) {
2607                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2608                                 x86_clear_reg (code, ins->backend.reg3);
2609                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
2610                         } else {
2611                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2612                                 x86_shift_reg_imm (code, X86_SHR, ins->backend.reg3, ins->inst_imm);
2613                         }
2614                         break;
2615                 case OP_INOT:
2616                         x86_not_reg (code, ins->sreg1);
2617                         break;
2618                 case OP_INEG:
2619                         x86_neg_reg (code, ins->sreg1);
2620                         break;
2621
2622                 case OP_IMUL:
2623                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2624                         break;
2625                 case OP_MUL_IMM:
2626                 case OP_IMUL_IMM:
2627                         switch (ins->inst_imm) {
2628                         case 2:
2629                                 /* MOV r1, r2 */
2630                                 /* ADD r1, r1 */
2631                                 if (ins->dreg != ins->sreg1)
2632                                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2633                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2634                                 break;
2635                         case 3:
2636                                 /* LEA r1, [r2 + r2*2] */
2637                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2638                                 break;
2639                         case 5:
2640                                 /* LEA r1, [r2 + r2*4] */
2641                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2642                                 break;
2643                         case 6:
2644                                 /* LEA r1, [r2 + r2*2] */
2645                                 /* ADD r1, r1          */
2646                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2647                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2648                                 break;
2649                         case 9:
2650                                 /* LEA r1, [r2 + r2*8] */
2651                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
2652                                 break;
2653                         case 10:
2654                                 /* LEA r1, [r2 + r2*4] */
2655                                 /* ADD r1, r1          */
2656                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2657                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2658                                 break;
2659                         case 12:
2660                                 /* LEA r1, [r2 + r2*2] */
2661                                 /* SHL r1, 2           */
2662                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2663                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2664                                 break;
2665                         case 25:
2666                                 /* LEA r1, [r2 + r2*4] */
2667                                 /* LEA r1, [r1 + r1*4] */
2668                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2669                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2670                                 break;
2671                         case 100:
2672                                 /* LEA r1, [r2 + r2*4] */
2673                                 /* SHL r1, 2           */
2674                                 /* LEA r1, [r1 + r1*4] */
2675                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2676                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2677                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2678                                 break;
2679                         default:
2680                                 x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2681                                 break;
2682                         }
2683                         break;
2684                 case OP_IMUL_OVF:
2685                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2686                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2687                         break;
2688                 case OP_IMUL_OVF_UN: {
2689                         /* the mul operation and the exception check should most likely be split */
2690                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
2691                         /*g_assert (ins->sreg2 == X86_EAX);
2692                         g_assert (ins->dreg == X86_EAX);*/
2693                         if (ins->sreg2 == X86_EAX) {
2694                                 non_eax_reg = ins->sreg1;
2695                         } else if (ins->sreg1 == X86_EAX) {
2696                                 non_eax_reg = ins->sreg2;
2697                         } else {
2698                                 /* no need to save since we're going to store to it anyway */
2699                                 if (ins->dreg != X86_EAX) {
2700                                         saved_eax = TRUE;
2701                                         x86_push_reg (code, X86_EAX);
2702                                 }
2703                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
2704                                 non_eax_reg = ins->sreg2;
2705                         }
2706                         if (ins->dreg == X86_EDX) {
2707                                 if (!saved_eax) {
2708                                         saved_eax = TRUE;
2709                                         x86_push_reg (code, X86_EAX);
2710                                 }
2711                         } else if (ins->dreg != X86_EAX) {
2712                                 saved_edx = TRUE;
2713                                 x86_push_reg (code, X86_EDX);
2714                         }
2715                         x86_mul_reg (code, non_eax_reg, FALSE);
2716                         /* save before the check since pop and mov don't change the flags */
2717                         if (ins->dreg != X86_EAX)
2718                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2719                         if (saved_edx)
2720                                 x86_pop_reg (code, X86_EDX);
2721                         if (saved_eax)
2722                                 x86_pop_reg (code, X86_EAX);
2723                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2724                         break;
2725                 }
2726                 case OP_ICONST:
2727                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
2728                         break;
2729                 case OP_AOTCONST:
2730                         g_assert_not_reached ();
2731                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2732                         x86_mov_reg_imm (code, ins->dreg, 0);
2733                         break;
2734                 case OP_JUMP_TABLE:
2735                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2736                         x86_mov_reg_imm (code, ins->dreg, 0);
2737                         break;
2738                 case OP_LOAD_GOTADDR:
2739                         x86_call_imm (code, 0);
2740                         /* 
2741                          * The patch needs to point to the pop, since the GOT offset needs 
2742                          * to be added to that address.
2743                          */
2744                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
2745                         x86_pop_reg (code, ins->dreg);
2746                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, 0xf0f0f0f0);
2747                         break;
2748                 case OP_GOT_ENTRY:
2749                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2750                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, 0xf0f0f0f0, 4);
2751                         break;
2752                 case OP_X86_PUSH_GOT_ENTRY:
2753                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2754                         x86_push_membase (code, ins->inst_basereg, 0xf0f0f0f0);
2755                         break;
2756                 case OP_MOVE:
2757                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2758                         break;
2759                 case OP_JMP: {
2760                         /*
2761                          * Note: this 'frame destruction' logic is useful for tail calls, too.
2762                          * Keep in sync with the code in emit_epilog.
2763                          */
2764                         int pos = 0;
2765
2766                         /* FIXME: no tracing support... */
2767                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2768                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
2769                         /* reset offset to make max_len work */
2770                         offset = code - cfg->native_code;
2771
2772                         g_assert (!cfg->method->save_lmf);
2773
2774                         code = emit_load_volatile_arguments (cfg, code);
2775
2776                         if (cfg->used_int_regs & (1 << X86_EBX))
2777                                 pos -= 4;
2778                         if (cfg->used_int_regs & (1 << X86_EDI))
2779                                 pos -= 4;
2780                         if (cfg->used_int_regs & (1 << X86_ESI))
2781                                 pos -= 4;
2782                         if (pos)
2783                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
2784         
2785                         if (cfg->used_int_regs & (1 << X86_ESI))
2786                                 x86_pop_reg (code, X86_ESI);
2787                         if (cfg->used_int_regs & (1 << X86_EDI))
2788                                 x86_pop_reg (code, X86_EDI);
2789                         if (cfg->used_int_regs & (1 << X86_EBX))
2790                                 x86_pop_reg (code, X86_EBX);
2791         
2792                         /* restore ESP/EBP */
2793                         x86_leave (code);
2794                         offset = code - cfg->native_code;
2795                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2796                         x86_jump32 (code, 0);
2797
2798                         cfg->disable_aot = TRUE;
2799                         break;
2800                 }
2801                 case OP_CHECK_THIS:
2802                         /* ensure ins->sreg1 is not NULL
2803                          * note that cmp DWORD PTR [eax], eax is one byte shorter than
2804                          * cmp DWORD PTR [eax], 0
2805                          */
2806                         x86_alu_membase_reg (code, X86_CMP, ins->sreg1, 0, ins->sreg1);
2807                         break;
2808                 case OP_ARGLIST: {
2809                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
2810                         x86_push_reg (code, hreg);
2811                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
2812                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
2813                         x86_pop_reg (code, hreg);
2814                         break;
2815                 }
2816                 case OP_FCALL:
2817                 case OP_LCALL:
2818                 case OP_VCALL:
2819                 case OP_VCALL2:
2820                 case OP_VOIDCALL:
2821                 case OP_CALL:
2822                         call = (MonoCallInst*)ins;
2823                         if (ins->flags & MONO_INST_HAS_METHOD)
2824                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2825                         else
2826                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2827                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2828                                 /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8
2829                                  * bytes to pop, we want to use pops. GCC does this (note it won't happen
2830                                  * for P4 or i686 because gcc will avoid using pop push at all. But we aren't
2831                                  * smart enough to do that optimization yet
2832                                  *
2833                                  * It turns out that on my P4, doing two pops for 8 bytes on the stack makes
2834                                  * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small,
2835                                  * (most likely from locality benefits). People with other processors should
2836                                  * check on theirs to see what happens.
2837                                  */
2838                                 if (call->stack_usage == 4) {
2839                                         /* we want to use registers that won't get used soon, so use
2840                                          * ecx, as eax will get allocated first. edx is used by long calls,
2841                                          * so we can't use that.
2842                                          */
2843                                         
2844                                         x86_pop_reg (code, X86_ECX);
2845                                 } else {
2846                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2847                                 }
2848                         }
2849                         code = emit_move_return_value (cfg, ins, code);
2850                         break;
2851                 case OP_FCALL_REG:
2852                 case OP_LCALL_REG:
2853                 case OP_VCALL_REG:
2854                 case OP_VCALL2_REG:
2855                 case OP_VOIDCALL_REG:
2856                 case OP_CALL_REG:
2857                         call = (MonoCallInst*)ins;
2858                         x86_call_reg (code, ins->sreg1);
2859                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2860                                 if (call->stack_usage == 4)
2861                                         x86_pop_reg (code, X86_ECX);
2862                                 else
2863                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2864                         }
2865                         code = emit_move_return_value (cfg, ins, code);
2866                         break;
2867                 case OP_FCALL_MEMBASE:
2868                 case OP_LCALL_MEMBASE:
2869                 case OP_VCALL_MEMBASE:
2870                 case OP_VCALL2_MEMBASE:
2871                 case OP_VOIDCALL_MEMBASE:
2872                 case OP_CALL_MEMBASE:
2873                         call = (MonoCallInst*)ins;
2874
2875                         /* 
2876                          * Emit a few nops to simplify get_vcall_slot ().
2877                          */
2878                         x86_nop (code);
2879                         x86_nop (code);
2880                         x86_nop (code);
2881
2882                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
2883                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2884                                 if (call->stack_usage == 4)
2885                                         x86_pop_reg (code, X86_ECX);
2886                                 else
2887                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2888                         }
2889                         code = emit_move_return_value (cfg, ins, code);
2890                         break;
2891                 case OP_X86_PUSH:
2892                         x86_push_reg (code, ins->sreg1);
2893                         break;
2894                 case OP_X86_PUSH_IMM:
2895                         x86_push_imm (code, ins->inst_imm);
2896                         break;
2897                 case OP_X86_PUSH_MEMBASE:
2898                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
2899                         break;
2900                 case OP_X86_PUSH_OBJ: 
2901                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
2902                         x86_push_reg (code, X86_EDI);
2903                         x86_push_reg (code, X86_ESI);
2904                         x86_push_reg (code, X86_ECX);
2905                         if (ins->inst_offset)
2906                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
2907                         else
2908                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
2909                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2910                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
2911                         x86_cld (code);
2912                         x86_prefix (code, X86_REP_PREFIX);
2913                         x86_movsd (code);
2914                         x86_pop_reg (code, X86_ECX);
2915                         x86_pop_reg (code, X86_ESI);
2916                         x86_pop_reg (code, X86_EDI);
2917                         break;
2918                 case OP_X86_LEA:
2919                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
2920                         break;
2921                 case OP_X86_LEA_MEMBASE:
2922                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
2923                         break;
2924                 case OP_X86_XCHG:
2925                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
2926                         break;
2927                 case OP_LOCALLOC:
2928                         /* keep alignment */
2929                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1);
2930                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2931                         code = mono_emit_stack_alloc (code, ins);
2932                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2933                         break;
2934                 case OP_LOCALLOC_IMM: {
2935                         guint32 size = ins->inst_imm;
2936                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2937
2938                         if (ins->flags & MONO_INST_INIT) {
2939                                 /* FIXME: Optimize this */
2940                                 x86_mov_reg_imm (code, ins->dreg, size);
2941                                 ins->sreg1 = ins->dreg;
2942
2943                                 code = mono_emit_stack_alloc (code, ins);
2944                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2945                         } else {
2946                                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, size);
2947                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2948                         }
2949                         break;
2950                 }
2951                 case OP_THROW: {
2952                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2953                         x86_push_reg (code, ins->sreg1);
2954                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2955                                                           (gpointer)"mono_arch_throw_exception");
2956                         break;
2957                 }
2958                 case OP_RETHROW: {
2959                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2960                         x86_push_reg (code, ins->sreg1);
2961                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2962                                                           (gpointer)"mono_arch_rethrow_exception");
2963                         break;
2964                 }
2965                 case OP_CALL_HANDLER:
2966                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2967                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2968                         x86_call_imm (code, 0);
2969                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
2970                         break;
2971                 case OP_START_HANDLER: {
2972                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2973                         x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
2974                         break;
2975                 }
2976                 case OP_ENDFINALLY: {
2977                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2978                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2979                         x86_ret (code);
2980                         break;
2981                 }
2982                 case OP_ENDFILTER: {
2983                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2984                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2985                         /* The local allocator will put the result into EAX */
2986                         x86_ret (code);
2987                         break;
2988                 }
2989
2990                 case OP_LABEL:
2991                         ins->inst_c0 = code - cfg->native_code;
2992                         break;
2993                 case OP_BR:
2994                         if (ins->inst_target_bb->native_offset) {
2995                                 x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2996                         } else {
2997                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2998                                 if ((cfg->opt & MONO_OPT_BRANCH) &&
2999                                     x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
3000                                         x86_jump8 (code, 0);
3001                                 else 
3002                                         x86_jump32 (code, 0);
3003                         }
3004                         break;
3005                 case OP_BR_REG:
3006                         x86_jump_reg (code, ins->sreg1);
3007                         break;
3008                 case OP_CEQ:
3009                 case OP_CLT:
3010                 case OP_CLT_UN:
3011                 case OP_CGT:
3012                 case OP_CGT_UN:
3013                 case OP_CNE:
3014                 case OP_ICEQ:
3015                 case OP_ICLT:
3016                 case OP_ICLT_UN:
3017                 case OP_ICGT:
3018                 case OP_ICGT_UN:
3019                         x86_set_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3020                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3021                         break;
3022                 case OP_COND_EXC_EQ:
3023                 case OP_COND_EXC_NE_UN:
3024                 case OP_COND_EXC_LT:
3025                 case OP_COND_EXC_LT_UN:
3026                 case OP_COND_EXC_GT:
3027                 case OP_COND_EXC_GT_UN:
3028                 case OP_COND_EXC_GE:
3029                 case OP_COND_EXC_GE_UN:
3030                 case OP_COND_EXC_LE:
3031                 case OP_COND_EXC_LE_UN:
3032                 case OP_COND_EXC_IEQ:
3033                 case OP_COND_EXC_INE_UN:
3034                 case OP_COND_EXC_ILT:
3035                 case OP_COND_EXC_ILT_UN:
3036                 case OP_COND_EXC_IGT:
3037                 case OP_COND_EXC_IGT_UN:
3038                 case OP_COND_EXC_IGE:
3039                 case OP_COND_EXC_IGE_UN:
3040                 case OP_COND_EXC_ILE:
3041                 case OP_COND_EXC_ILE_UN:
3042                         EMIT_COND_SYSTEM_EXCEPTION (cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->inst_p1);
3043                         break;
3044                 case OP_COND_EXC_OV:
3045                 case OP_COND_EXC_NO:
3046                 case OP_COND_EXC_C:
3047                 case OP_COND_EXC_NC:
3048                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
3049                         break;
3050                 case OP_COND_EXC_IOV:
3051                 case OP_COND_EXC_INO:
3052                 case OP_COND_EXC_IC:
3053                 case OP_COND_EXC_INC:
3054                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), ins->inst_p1);
3055                         break;
3056                 case OP_IBEQ:
3057                 case OP_IBNE_UN:
3058                 case OP_IBLT:
3059                 case OP_IBLT_UN:
3060                 case OP_IBGT:
3061                 case OP_IBGT_UN:
3062                 case OP_IBGE:
3063                 case OP_IBGE_UN:
3064                 case OP_IBLE:
3065                 case OP_IBLE_UN:
3066                         EMIT_COND_BRANCH (ins, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3067                         break;
3068
3069                 case OP_CMOV_IEQ:
3070                 case OP_CMOV_IGE:
3071                 case OP_CMOV_IGT:
3072                 case OP_CMOV_ILE:
3073                 case OP_CMOV_ILT:
3074                 case OP_CMOV_INE_UN:
3075                 case OP_CMOV_IGE_UN:
3076                 case OP_CMOV_IGT_UN:
3077                 case OP_CMOV_ILE_UN:
3078                 case OP_CMOV_ILT_UN:
3079                         g_assert (ins->dreg == ins->sreg1);
3080                         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);
3081                         break;
3082
3083                 /* floating point opcodes */
3084                 case OP_R8CONST: {
3085                         double d = *(double *)ins->inst_p0;
3086
3087                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
3088                                 x86_fldz (code);
3089                         } else if (d == 1.0) {
3090                                 x86_fld1 (code);
3091                         } else {
3092                                 if (cfg->compile_aot) {
3093                                         guint32 *val = (guint32*)&d;
3094                                         x86_push_imm (code, val [1]);
3095                                         x86_push_imm (code, val [0]);
3096                                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3097                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3098                                 }
3099                                 else {
3100                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R8, ins->inst_p0);
3101                                         x86_fld (code, NULL, TRUE);
3102                                 }
3103                         }
3104                         break;
3105                 }
3106                 case OP_R4CONST: {
3107                         float f = *(float *)ins->inst_p0;
3108
3109                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
3110                                 x86_fldz (code);
3111                         } else if (f == 1.0) {
3112                                 x86_fld1 (code);
3113                         } else {
3114                                 if (cfg->compile_aot) {
3115                                         guint32 val = *(guint32*)&f;
3116                                         x86_push_imm (code, val);
3117                                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3118                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3119                                 }
3120                                 else {
3121                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R4, ins->inst_p0);
3122                                         x86_fld (code, NULL, FALSE);
3123                                 }
3124                         }
3125                         break;
3126                 }
3127                 case OP_STORER8_MEMBASE_REG:
3128                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
3129                         break;
3130                 case OP_LOADR8_MEMBASE:
3131                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3132                         break;
3133                 case OP_STORER4_MEMBASE_REG:
3134                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
3135                         break;
3136                 case OP_LOADR4_MEMBASE:
3137                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3138                         break;
3139                 case OP_ICONV_TO_R4:
3140                         x86_push_reg (code, ins->sreg1);
3141                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3142                         /* Change precision */
3143                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3144                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3145                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3146                         break;
3147                 case OP_ICONV_TO_R8:
3148                         x86_push_reg (code, ins->sreg1);
3149                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3150                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3151                         break;
3152                 case OP_ICONV_TO_R_UN:
3153                         x86_push_imm (code, 0);
3154                         x86_push_reg (code, ins->sreg1);
3155                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3156                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3157                         break;
3158                 case OP_X86_FP_LOAD_I8:
3159                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3160                         break;
3161                 case OP_X86_FP_LOAD_I4:
3162                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3163                         break;
3164                 case OP_FCONV_TO_R4:
3165                         /* Change precision */
3166                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3167                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3168                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3169                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3170                         break;
3171                 case OP_FCONV_TO_I1:
3172                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
3173                         break;
3174                 case OP_FCONV_TO_U1:
3175                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
3176                         break;
3177                 case OP_FCONV_TO_I2:
3178                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
3179                         break;
3180                 case OP_FCONV_TO_U2:
3181                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
3182                         break;
3183                 case OP_FCONV_TO_I4:
3184                 case OP_FCONV_TO_I:
3185                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
3186                         break;
3187                 case OP_FCONV_TO_I8:
3188                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3189                         x86_fnstcw_membase(code, X86_ESP, 0);
3190                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
3191                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
3192                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
3193                         x86_fldcw_membase (code, X86_ESP, 2);
3194                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3195                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
3196                         x86_pop_reg (code, ins->dreg);
3197                         x86_pop_reg (code, ins->backend.reg3);
3198                         x86_fldcw_membase (code, X86_ESP, 0);
3199                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3200                         break;
3201                 case OP_LCONV_TO_R8_2:
3202                         x86_push_reg (code, ins->sreg2);
3203                         x86_push_reg (code, ins->sreg1);
3204                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3205                         /* Change precision */
3206                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3207                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3208                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3209                         break;
3210                 case OP_LCONV_TO_R4_2:
3211                         x86_push_reg (code, ins->sreg2);
3212                         x86_push_reg (code, ins->sreg1);
3213                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3214                         /* Change precision */
3215                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3216                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3217                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3218                         break;
3219                 case OP_LCONV_TO_R_UN_2: { 
3220                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3221                         guint8 *br;
3222
3223                         /* load 64bit integer to FP stack */
3224                         x86_push_reg (code, ins->sreg2);
3225                         x86_push_reg (code, ins->sreg1);
3226                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3227                         
3228                         /* test if lreg is negative */
3229                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3230                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
3231         
3232                         /* add correction constant mn */
3233                         x86_fld80_mem (code, mn);
3234                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3235
3236                         x86_patch (br, code);
3237
3238                         /* Change precision */
3239                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3240                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3241
3242                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3243
3244                         break;
3245                 }
3246                 case OP_LCONV_TO_OVF_I:
3247                 case OP_LCONV_TO_OVF_I4_2: {
3248                         guint8 *br [3], *label [1];
3249                         MonoInst *tins;
3250
3251                         /* 
3252                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3253                          */
3254                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
3255
3256                         /* If the low word top bit is set, see if we are negative */
3257                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
3258                         /* We are not negative (no top bit set, check for our top word to be zero */
3259                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3260                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
3261                         label [0] = code;
3262
3263                         /* throw exception */
3264                         tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
3265                         if (tins) {
3266                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
3267                                 if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
3268                                         x86_jump8 (code, 0);
3269                                 else
3270                                         x86_jump32 (code, 0);
3271                         } else {
3272                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
3273                                 x86_jump32 (code, 0);
3274                         }
3275         
3276         
3277                         x86_patch (br [0], code);
3278                         /* our top bit is set, check that top word is 0xfffffff */
3279                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
3280                 
3281                         x86_patch (br [1], code);
3282                         /* nope, emit exception */
3283                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
3284                         x86_patch (br [2], label [0]);
3285
3286                         if (ins->dreg != ins->sreg1)
3287                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3288                         break;
3289                 }
3290                 case OP_FMOVE:
3291                         /* Not needed on the fp stack */
3292                         break;
3293                 case OP_FADD:
3294                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3295                         break;
3296                 case OP_FSUB:
3297                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
3298                         break;          
3299                 case OP_FMUL:
3300                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
3301                         break;          
3302                 case OP_FDIV:
3303                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
3304                         break;          
3305                 case OP_FNEG:
3306                         x86_fchs (code);
3307                         break;          
3308                 case OP_SIN:
3309                         x86_fsin (code);
3310                         x86_fldz (code);
3311                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3312                         break;          
3313                 case OP_COS:
3314                         x86_fcos (code);
3315                         x86_fldz (code);
3316                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3317                         break;          
3318                 case OP_ABS:
3319                         x86_fabs (code);
3320                         break;          
3321                 case OP_TAN: {
3322                         /* 
3323                          * it really doesn't make sense to inline all this code,
3324                          * it's here just to show that things may not be as simple 
3325                          * as they appear.
3326                          */
3327                         guchar *check_pos, *end_tan, *pop_jump;
3328                         x86_push_reg (code, X86_EAX);
3329                         x86_fptan (code);
3330                         x86_fnstsw (code);
3331                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3332                         check_pos = code;
3333                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3334                         x86_fstp (code, 0); /* pop the 1.0 */
3335                         end_tan = code;
3336                         x86_jump8 (code, 0);
3337                         x86_fldpi (code);
3338                         x86_fp_op (code, X86_FADD, 0);
3339                         x86_fxch (code, 1);
3340                         x86_fprem1 (code);
3341                         x86_fstsw (code);
3342                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3343                         pop_jump = code;
3344                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3345                         x86_fstp (code, 1);
3346                         x86_fptan (code);
3347                         x86_patch (pop_jump, code);
3348                         x86_fstp (code, 0); /* pop the 1.0 */
3349                         x86_patch (check_pos, code);
3350                         x86_patch (end_tan, code);
3351                         x86_fldz (code);
3352                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3353                         x86_pop_reg (code, X86_EAX);
3354                         break;
3355                 }
3356                 case OP_ATAN:
3357                         x86_fld1 (code);
3358                         x86_fpatan (code);
3359                         x86_fldz (code);
3360                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3361                         break;          
3362                 case OP_SQRT:
3363                         x86_fsqrt (code);
3364                         break;
3365                 case OP_ROUND:
3366                         x86_frndint (code);
3367                         break;
3368                 case OP_IMIN:
3369                         g_assert (cfg->opt & MONO_OPT_CMOV);
3370                         g_assert (ins->dreg == ins->sreg1);
3371                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3372                         x86_cmov_reg (code, X86_CC_GT, TRUE, ins->dreg, ins->sreg2);
3373                         break;
3374                 case OP_IMIN_UN:
3375                         g_assert (cfg->opt & MONO_OPT_CMOV);
3376                         g_assert (ins->dreg == ins->sreg1);
3377                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3378                         x86_cmov_reg (code, X86_CC_GT, FALSE, ins->dreg, ins->sreg2);
3379                         break;
3380                 case OP_IMAX:
3381                         g_assert (cfg->opt & MONO_OPT_CMOV);
3382                         g_assert (ins->dreg == ins->sreg1);
3383                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3384                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
3385                         break;
3386                 case OP_IMAX_UN:
3387                         g_assert (cfg->opt & MONO_OPT_CMOV);
3388                         g_assert (ins->dreg == ins->sreg1);
3389                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3390                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
3391                         break;
3392                 case OP_X86_FPOP:
3393                         x86_fstp (code, 0);
3394                         break;
3395                 case OP_X86_FXCH:
3396                         x86_fxch (code, ins->inst_imm);
3397                         break;
3398                 case OP_FREM: {
3399                         guint8 *l1, *l2;
3400
3401                         x86_push_reg (code, X86_EAX);
3402                         /* we need to exchange ST(0) with ST(1) */
3403                         x86_fxch (code, 1);
3404
3405                         /* this requires a loop, because fprem somtimes 
3406                          * returns a partial remainder */
3407                         l1 = code;
3408                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3409                         /* x86_fprem1 (code); */
3410                         x86_fprem (code);
3411                         x86_fnstsw (code);
3412                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3413                         l2 = code + 2;
3414                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3415
3416                         /* pop result */
3417                         x86_fstp (code, 1);
3418
3419                         x86_pop_reg (code, X86_EAX);
3420                         break;
3421                 }
3422                 case OP_FCOMPARE:
3423                         if (cfg->opt & MONO_OPT_FCMOV) {
3424                                 x86_fcomip (code, 1);
3425                                 x86_fstp (code, 0);
3426                                 break;
3427                         }
3428                         /* this overwrites EAX */
3429                         EMIT_FPCOMPARE(code);
3430                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3431                         break;
3432                 case OP_FCEQ:
3433                         if (cfg->opt & MONO_OPT_FCMOV) {
3434                                 /* zeroing the register at the start results in 
3435                                  * shorter and faster code (we can also remove the widening op)
3436                                  */
3437                                 guchar *unordered_check;
3438                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3439                                 x86_fcomip (code, 1);
3440                                 x86_fstp (code, 0);
3441                                 unordered_check = code;
3442                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3443                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3444                                 x86_patch (unordered_check, code);
3445                                 break;
3446                         }
3447                         if (ins->dreg != X86_EAX) 
3448                                 x86_push_reg (code, X86_EAX);
3449
3450                         EMIT_FPCOMPARE(code);
3451                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3452                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3453                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3454                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3455
3456                         if (ins->dreg != X86_EAX) 
3457                                 x86_pop_reg (code, X86_EAX);
3458                         break;
3459                 case OP_FCLT:
3460                 case OP_FCLT_UN:
3461                         if (cfg->opt & MONO_OPT_FCMOV) {
3462                                 /* zeroing the register at the start results in 
3463                                  * shorter and faster code (we can also remove the widening op)
3464                                  */
3465                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3466                                 x86_fcomip (code, 1);
3467                                 x86_fstp (code, 0);
3468                                 if (ins->opcode == OP_FCLT_UN) {
3469                                         guchar *unordered_check = code;
3470                                         guchar *jump_to_end;
3471                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3472                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3473                                         jump_to_end = code;
3474                                         x86_jump8 (code, 0);
3475                                         x86_patch (unordered_check, code);
3476                                         x86_inc_reg (code, ins->dreg);
3477                                         x86_patch (jump_to_end, code);
3478                                 } else {
3479                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3480                                 }
3481                                 break;
3482                         }
3483                         if (ins->dreg != X86_EAX) 
3484                                 x86_push_reg (code, X86_EAX);
3485
3486                         EMIT_FPCOMPARE(code);
3487                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3488                         if (ins->opcode == OP_FCLT_UN) {
3489                                 guchar *is_not_zero_check, *end_jump;
3490                                 is_not_zero_check = code;
3491                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3492                                 end_jump = code;
3493                                 x86_jump8 (code, 0);
3494                                 x86_patch (is_not_zero_check, code);
3495                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3496
3497                                 x86_patch (end_jump, code);
3498                         }
3499                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3500                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3501
3502                         if (ins->dreg != X86_EAX) 
3503                                 x86_pop_reg (code, X86_EAX);
3504                         break;
3505                 case OP_FCGT:
3506                 case OP_FCGT_UN:
3507                         if (cfg->opt & MONO_OPT_FCMOV) {
3508                                 /* zeroing the register at the start results in 
3509                                  * shorter and faster code (we can also remove the widening op)
3510                                  */
3511                                 guchar *unordered_check;
3512                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3513                                 x86_fcomip (code, 1);
3514                                 x86_fstp (code, 0);
3515                                 if (ins->opcode == OP_FCGT) {
3516                                         unordered_check = code;
3517                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3518                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3519                                         x86_patch (unordered_check, code);
3520                                 } else {
3521                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3522                                 }
3523                                 break;
3524                         }
3525                         if (ins->dreg != X86_EAX) 
3526                                 x86_push_reg (code, X86_EAX);
3527
3528                         EMIT_FPCOMPARE(code);
3529                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3530                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3531                         if (ins->opcode == OP_FCGT_UN) {
3532                                 guchar *is_not_zero_check, *end_jump;
3533                                 is_not_zero_check = code;
3534                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3535                                 end_jump = code;
3536                                 x86_jump8 (code, 0);
3537                                 x86_patch (is_not_zero_check, code);
3538                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3539         
3540                                 x86_patch (end_jump, code);
3541                         }
3542                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3543                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3544
3545                         if (ins->dreg != X86_EAX) 
3546                                 x86_pop_reg (code, X86_EAX);
3547                         break;
3548                 case OP_FBEQ:
3549                         if (cfg->opt & MONO_OPT_FCMOV) {
3550                                 guchar *jump = code;
3551                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3552                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3553                                 x86_patch (jump, code);
3554                                 break;
3555                         }
3556                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3557                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3558                         break;
3559                 case OP_FBNE_UN:
3560                         /* Branch if C013 != 100 */
3561                         if (cfg->opt & MONO_OPT_FCMOV) {
3562                                 /* branch if !ZF or (PF|CF) */
3563                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3564                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3565                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3566                                 break;
3567                         }
3568                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3569                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3570                         break;
3571                 case OP_FBLT:
3572                         if (cfg->opt & MONO_OPT_FCMOV) {
3573                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3574                                 break;
3575                         }
3576                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3577                         break;
3578                 case OP_FBLT_UN:
3579                         if (cfg->opt & MONO_OPT_FCMOV) {
3580                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3581                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3582                                 break;
3583                         }
3584                         if (ins->opcode == OP_FBLT_UN) {
3585                                 guchar *is_not_zero_check, *end_jump;
3586                                 is_not_zero_check = code;
3587                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3588                                 end_jump = code;
3589                                 x86_jump8 (code, 0);
3590                                 x86_patch (is_not_zero_check, code);
3591                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3592
3593                                 x86_patch (end_jump, code);
3594                         }
3595                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3596                         break;
3597                 case OP_FBGT:
3598                 case OP_FBGT_UN:
3599                         if (cfg->opt & MONO_OPT_FCMOV) {
3600                                 if (ins->opcode == OP_FBGT) {
3601                                         guchar *br1;
3602
3603                                         /* skip branch if C1=1 */
3604                                         br1 = code;
3605                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3606                                         /* branch if (C0 | C3) = 1 */
3607                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3608                                         x86_patch (br1, code);
3609                                 } else {
3610                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3611                                 }
3612                                 break;
3613                         }
3614                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3615                         if (ins->opcode == OP_FBGT_UN) {
3616                                 guchar *is_not_zero_check, *end_jump;
3617                                 is_not_zero_check = code;
3618                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3619                                 end_jump = code;
3620                                 x86_jump8 (code, 0);
3621                                 x86_patch (is_not_zero_check, code);
3622                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3623
3624                                 x86_patch (end_jump, code);
3625                         }
3626                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3627                         break;
3628                 case OP_FBGE:
3629                         /* Branch if C013 == 100 or 001 */
3630                         if (cfg->opt & MONO_OPT_FCMOV) {
3631                                 guchar *br1;
3632
3633                                 /* skip branch if C1=1 */
3634                                 br1 = code;
3635                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3636                                 /* branch if (C0 | C3) = 1 */
3637                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3638                                 x86_patch (br1, code);
3639                                 break;
3640                         }
3641                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3642                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3643                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3644                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3645                         break;
3646                 case OP_FBGE_UN:
3647                         /* Branch if C013 == 000 */
3648                         if (cfg->opt & MONO_OPT_FCMOV) {
3649                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3650                                 break;
3651                         }
3652                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3653                         break;
3654                 case OP_FBLE:
3655                         /* Branch if C013=000 or 100 */
3656                         if (cfg->opt & MONO_OPT_FCMOV) {
3657                                 guchar *br1;
3658
3659                                 /* skip branch if C1=1 */
3660                                 br1 = code;
3661                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3662                                 /* branch if C0=0 */
3663                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3664                                 x86_patch (br1, code);
3665                                 break;
3666                         }
3667                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3668                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3669                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3670                         break;
3671                 case OP_FBLE_UN:
3672                         /* Branch if C013 != 001 */
3673                         if (cfg->opt & MONO_OPT_FCMOV) {
3674                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3675                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3676                                 break;
3677                         }
3678                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3679                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3680                         break;
3681                 case OP_CKFINITE: {
3682                         guchar *br1;
3683                         x86_push_reg (code, X86_EAX);
3684                         x86_fxam (code);
3685                         x86_fnstsw (code);
3686                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3687                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3688                         x86_pop_reg (code, X86_EAX);
3689
3690                         /* Have to clean up the fp stack before throwing the exception */
3691                         br1 = code;
3692                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3693
3694                         x86_fstp (code, 0);                     
3695                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3696
3697                         x86_patch (br1, code);
3698                         break;
3699                 }
3700                 case OP_TLS_GET: {
3701                         code = mono_x86_emit_tls_get (code, ins->dreg, ins->inst_offset);
3702                         break;
3703                 }
3704                 case OP_MEMORY_BARRIER: {
3705                         /* Not needed on x86 */
3706                         break;
3707                 }
3708                 case OP_ATOMIC_ADD_I4: {
3709                         int dreg = ins->dreg;
3710
3711                         if (dreg == ins->inst_basereg) {
3712                                 x86_push_reg (code, ins->sreg2);
3713                                 dreg = ins->sreg2;
3714                         } 
3715                         
3716                         if (dreg != ins->sreg2)
3717                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
3718
3719                         x86_prefix (code, X86_LOCK_PREFIX);
3720                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3721
3722                         if (dreg != ins->dreg) {
3723                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3724                                 x86_pop_reg (code, dreg);
3725                         }
3726
3727                         break;
3728                 }
3729                 case OP_ATOMIC_ADD_NEW_I4: {
3730                         int dreg = ins->dreg;
3731
3732                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
3733                         if (ins->sreg2 == dreg) {
3734                                 if (dreg == X86_EBX) {
3735                                         dreg = X86_EDI;
3736                                         if (ins->inst_basereg == X86_EDI)
3737                                                 dreg = X86_ESI;
3738                                 } else {
3739                                         dreg = X86_EBX;
3740                                         if (ins->inst_basereg == X86_EBX)
3741                                                 dreg = X86_EDI;
3742                                 }
3743                         } else if (ins->inst_basereg == dreg) {
3744                                 if (dreg == X86_EBX) {
3745                                         dreg = X86_EDI;
3746                                         if (ins->sreg2 == X86_EDI)
3747                                                 dreg = X86_ESI;
3748                                 } else {
3749                                         dreg = X86_EBX;
3750                                         if (ins->sreg2 == X86_EBX)
3751                                                 dreg = X86_EDI;
3752                                 }
3753                         }
3754
3755                         if (dreg != ins->dreg) {
3756                                 x86_push_reg (code, dreg);
3757                         }
3758
3759                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
3760                         x86_prefix (code, X86_LOCK_PREFIX);
3761                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3762                         /* dreg contains the old value, add with sreg2 value */
3763                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
3764                         
3765                         if (ins->dreg != dreg) {
3766                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3767                                 x86_pop_reg (code, dreg);
3768                         }
3769
3770                         break;
3771                 }
3772                 case OP_ATOMIC_EXCHANGE_I4: {
3773                         guchar *br[2];
3774                         int sreg2 = ins->sreg2;
3775                         int breg = ins->inst_basereg;
3776
3777                         /* cmpxchg uses eax as comperand, need to make sure we can use it
3778                          * hack to overcome limits in x86 reg allocator 
3779                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
3780                          */
3781                         g_assert (ins->dreg == X86_EAX);
3782                         
3783                         /* We need the EAX reg for the cmpxchg */
3784                         if (ins->sreg2 == X86_EAX) {
3785                                 sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX;
3786                                 x86_push_reg (code, sreg2);
3787                                 x86_mov_reg_reg (code, sreg2, X86_EAX, 4);
3788                         }
3789
3790                         if (breg == X86_EAX) {
3791                                 breg = (sreg2 == X86_ESI) ? X86_EDI : X86_ESI;
3792                                 x86_push_reg (code, breg);
3793                                 x86_mov_reg_reg (code, breg, X86_EAX, 4);
3794                         }
3795
3796                         x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
3797
3798                         br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
3799                         x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3800                         br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
3801                         x86_patch (br [1], br [0]);
3802
3803                         if (breg != ins->inst_basereg)
3804                                 x86_pop_reg (code, breg);
3805
3806                         if (ins->sreg2 != sreg2)
3807                                 x86_pop_reg (code, sreg2);
3808
3809                         break;
3810                 }
3811                 case OP_ATOMIC_CAS_I4: {
3812                         g_assert (ins->sreg3 == X86_EAX);
3813                         g_assert (ins->sreg1 != X86_EAX);
3814                         g_assert (ins->sreg1 != ins->sreg2);
3815
3816                         x86_prefix (code, X86_LOCK_PREFIX);
3817                         x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
3818
3819                         if (ins->dreg != X86_EAX)
3820                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
3821                         break;
3822                 }
3823 #ifdef MONO_ARCH_SIMD_INTRINSICS
3824                 case OP_ADDPS:
3825                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
3826                         break;
3827                 case OP_DIVPS:
3828                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
3829                         break;
3830                 case OP_MULPS:
3831                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
3832                         break;
3833                 case OP_SUBPS:
3834                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
3835                         break;
3836                 case OP_MAXPS:
3837                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
3838                         break;
3839                 case OP_MINPS:
3840                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
3841                         break;
3842                 case OP_COMPPS:
3843                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
3844                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
3845                         break;
3846                 case OP_ANDPS:
3847                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
3848                         break;
3849                 case OP_ANDNPS:
3850                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
3851                         break;
3852                 case OP_ORPS:
3853                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
3854                         break;
3855                 case OP_XORPS:
3856                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
3857                         break;
3858                 case OP_SQRTPS:
3859                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
3860                         break;
3861                 case OP_RSQRTPS:
3862                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
3863                         break;
3864                 case OP_RCPPS:
3865                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
3866                         break;
3867                 case OP_ADDSUBPS:
3868                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
3869                         break;
3870                 case OP_HADDPS:
3871                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
3872                         break;
3873                 case OP_HSUBPS:
3874                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
3875                         break;
3876                 case OP_DUPPS_HIGH:
3877                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
3878                         break;
3879                 case OP_DUPPS_LOW:
3880                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
3881                         break;
3882
3883                 case OP_PSHUFLEW_HIGH:
3884                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3885                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
3886                         break;
3887                 case OP_PSHUFLEW_LOW:
3888                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3889                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
3890                         break;
3891                 case OP_PSHUFLED:
3892                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3893                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
3894                         break;
3895
3896                 case OP_ADDPD:
3897                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
3898                         break;
3899                 case OP_DIVPD:
3900                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
3901                         break;
3902                 case OP_MULPD:
3903                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
3904                         break;
3905                 case OP_SUBPD:
3906                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
3907                         break;
3908                 case OP_MAXPD:
3909                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
3910                         break;
3911                 case OP_MINPD:
3912                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
3913                         break;
3914                 case OP_COMPPD:
3915                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
3916                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
3917                         break;
3918                 case OP_ANDPD:
3919                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
3920                         break;
3921                 case OP_ANDNPD:
3922                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
3923                         break;
3924                 case OP_ORPD:
3925                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
3926                         break;
3927                 case OP_XORPD:
3928                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
3929                         break;
3930                 case OP_SQRTPD:
3931                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
3932                         break;
3933                 case OP_ADDSUBPD:
3934                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
3935                         break;
3936                 case OP_HADDPD:
3937                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
3938                         break;
3939                 case OP_HSUBPD:
3940                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
3941                         break;
3942                 case OP_DUPPD:
3943                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
3944                         break;
3945                         
3946                 case OP_EXTRACT_MASK:
3947                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
3948                         break;
3949         
3950                 case OP_PAND:
3951                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
3952                         break;
3953                 case OP_POR:
3954                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
3955                         break;
3956                 case OP_PXOR:
3957                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
3958                         break;
3959
3960                 case OP_PADDB:
3961                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
3962                         break;
3963                 case OP_PADDW:
3964                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
3965                         break;
3966                 case OP_PADDD:
3967                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
3968                         break;
3969                 case OP_PADDQ:
3970                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
3971                         break;
3972
3973                 case OP_PSUBB:
3974                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
3975                         break;
3976                 case OP_PSUBW:
3977                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
3978                         break;
3979                 case OP_PSUBD:
3980                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
3981                         break;
3982                 case OP_PSUBQ:
3983                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
3984                         break;
3985
3986                 case OP_PMAXB_UN:
3987                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
3988                         break;
3989                 case OP_PMAXW_UN:
3990                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
3991                         break;
3992                 case OP_PMAXD_UN:
3993                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
3994                         break;
3995                 
3996                 case OP_PMAXB:
3997                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
3998                         break;
3999                 case OP_PMAXW:
4000                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
4001                         break;
4002                 case OP_PMAXD:
4003                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4004                         break;
4005
4006                 case OP_PAVGB_UN:
4007                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4008                         break;
4009                 case OP_PAVGW_UN:
4010                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4011                         break;
4012
4013                 case OP_PMINB_UN:
4014                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4015                         break;
4016                 case OP_PMINW_UN:
4017                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4018                         break;
4019                 case OP_PMIND_UN:
4020                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4021                         break;
4022
4023                 case OP_PMINB:
4024                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4025                         break;
4026                 case OP_PMINW:
4027                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4028                         break;
4029                 case OP_PMIND:
4030                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4031                         break;
4032
4033                 case OP_PCMPEQB:
4034                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4035                         break;
4036                 case OP_PCMPEQW:
4037                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4038                         break;
4039                 case OP_PCMPEQD:
4040                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4041                         break;
4042                 case OP_PCMPEQQ:
4043                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4044                         break;
4045
4046                 case OP_PCMPGTB:
4047                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4048                         break;
4049                 case OP_PCMPGTW:
4050                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4051                         break;
4052                 case OP_PCMPGTD:
4053                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4054                         break;
4055                 case OP_PCMPGTQ:
4056                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4057                         break;
4058
4059                 case OP_PSUM_ABS_DIFF:
4060                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4061                         break;
4062
4063                 case OP_UNPACK_LOWB:
4064                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4065                         break;
4066                 case OP_UNPACK_LOWW:
4067                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4068                         break;
4069                 case OP_UNPACK_LOWD:
4070                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4071                         break;
4072                 case OP_UNPACK_LOWQ:
4073                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4074                         break;
4075                 case OP_UNPACK_LOWPS:
4076                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4077                         break;
4078                 case OP_UNPACK_LOWPD:
4079                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4080                         break;
4081
4082                 case OP_UNPACK_HIGHB:
4083                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4084                         break;
4085                 case OP_UNPACK_HIGHW:
4086                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4087                         break;
4088                 case OP_UNPACK_HIGHD:
4089                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4090                         break;
4091                 case OP_UNPACK_HIGHQ:
4092                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4093                         break;
4094                 case OP_UNPACK_HIGHPS:
4095                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4096                         break;
4097                 case OP_UNPACK_HIGHPD:
4098                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4099                         break;
4100
4101                 case OP_PACKW:
4102                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4103                         break;
4104                 case OP_PACKD:
4105                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4106                         break;
4107                 case OP_PACKW_UN:
4108                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4109                         break;
4110                 case OP_PACKD_UN:
4111                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4112                         break;
4113
4114                 case OP_PADDB_SAT_UN:
4115                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4116                         break;
4117                 case OP_PSUBB_SAT_UN:
4118                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4119                         break;
4120                 case OP_PADDW_SAT_UN:
4121                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4122                         break;
4123                 case OP_PSUBW_SAT_UN:
4124                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4125                         break;
4126
4127                 case OP_PADDB_SAT:
4128                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4129                         break;
4130                 case OP_PSUBB_SAT:
4131                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4132                         break;
4133                 case OP_PADDW_SAT:
4134                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4135                         break;
4136                 case OP_PSUBW_SAT:
4137                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4138                         break;
4139                         
4140                 case OP_PMULW:
4141                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4142                         break;
4143                 case OP_PMULD:
4144                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4145                         break;
4146                 case OP_PMULQ:
4147                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4148                         break;
4149                 case OP_PMULW_HIGH_UN:
4150                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4151                         break;
4152                 case OP_PMULW_HIGH:
4153                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4154                         break;
4155
4156                 case OP_PSHRW:
4157                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4158                         break;
4159                 case OP_PSHRW_REG:
4160                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4161                         break;
4162
4163                 case OP_PSARW:
4164                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4165                         break;
4166                 case OP_PSARW_REG:
4167                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4168                         break;
4169
4170                 case OP_PSHLW:
4171                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4172                         break;
4173                 case OP_PSHLW_REG:
4174                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4175                         break;
4176
4177                 case OP_PSHRD:
4178                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4179                         break;
4180                 case OP_PSHRD_REG:
4181                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4182                         break;
4183
4184                 case OP_PSARD:
4185                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4186                         break;
4187                 case OP_PSARD_REG:
4188                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4189                         break;
4190
4191                 case OP_PSHLD:
4192                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4193                         break;
4194                 case OP_PSHLD_REG:
4195                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4196                         break;
4197
4198                 case OP_PSHRQ:
4199                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4200                         break;
4201                 case OP_PSHRQ_REG:
4202                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4203                         break;
4204
4205                 case OP_PSHLQ:
4206                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4207                         break;
4208                 case OP_PSHLQ_REG:
4209                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4210                         break;          
4211                         
4212                 case OP_ICONV_TO_X:
4213                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4214                         break;
4215                 case OP_EXTRACT_I4:
4216                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4217                         break;
4218                 case OP_EXTRACT_I1:
4219                 case OP_EXTRACT_U1:
4220                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4221                         if (ins->inst_c0)
4222                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4223                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4224                         break;
4225                 case OP_EXTRACT_I2:
4226                 case OP_EXTRACT_U2:
4227                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4228                         if (ins->inst_c0)
4229                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4230                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4231                         break;
4232                 case OP_EXTRACT_R8:
4233                         if (ins->inst_c0)
4234                                 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);
4235                         else
4236                                 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);
4237                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4238                         break;
4239
4240                 case OP_INSERT_I2:
4241                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4242                         break;
4243                 case OP_EXTRACTX_U2:
4244                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4245                         break;
4246                 case OP_INSERTX_U1_SLOW:
4247                         /*sreg1 is the extracted ireg (scratch)
4248                         /sreg2 is the to be inserted ireg (scratch)
4249                         /dreg is the xreg to receive the value*/
4250
4251                         /*clear the bits from the extracted word*/
4252                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4253                         /*shift the value to insert if needed*/
4254                         if (ins->inst_c0 & 1)
4255                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4256                         /*join them together*/
4257                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4258                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4259                         break;
4260                 case OP_INSERTX_I4_SLOW:
4261                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4262                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4263                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4264                         break;
4265
4266                 case OP_INSERTX_R4_SLOW:
4267                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4268                         /*TODO if inst_c0 == 0 use movss*/
4269                         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);
4270                         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);
4271                         break;
4272                 case OP_INSERTX_R8_SLOW:
4273                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4274                         if (ins->inst_c0)
4275                                 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);
4276                         else
4277                                 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);
4278                         break;
4279
4280                 case OP_STOREX_MEMBASE_REG:
4281                 case OP_STOREX_MEMBASE:
4282                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4283                         break;
4284                 case OP_LOADX_MEMBASE:
4285                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4286                         break;
4287                 case OP_LOADX_ALIGNED_MEMBASE:
4288                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4289                         break;
4290                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4291                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4292                         break;
4293                 case OP_STOREX_NTA_MEMBASE_REG:
4294                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4295                         break;
4296                 case OP_PREFETCH_MEMBASE:
4297                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4298
4299                         break;
4300                 case OP_XMOVE:
4301                         /*FIXME the peephole pass should have killed this*/
4302                         if (ins->dreg != ins->sreg1)
4303                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4304                         break;          
4305                 case OP_XZERO:
4306                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4307                         break;
4308                 case OP_ICONV_TO_R8_RAW:
4309                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4310                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4311                         break;
4312
4313                 case OP_FCONV_TO_R8_X:
4314                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4315                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4316                         break;
4317
4318                 case OP_XCONV_R8_TO_I4:
4319                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4320                         switch (ins->backend.source_opcode) {
4321                         case OP_FCONV_TO_I1:
4322                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4323                                 break;
4324                         case OP_FCONV_TO_U1:
4325                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4326                                 break;
4327                         case OP_FCONV_TO_I2:
4328                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4329                                 break;
4330                         case OP_FCONV_TO_U2:
4331                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4332                                 break;
4333                         }                       
4334                         break;
4335
4336                 case OP_EXPAND_I1:
4337                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4338                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4339                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4340                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4341                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4342                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4343                         break;
4344                 case OP_EXPAND_I2:
4345                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4346                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4347                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4348                         break;
4349                 case OP_EXPAND_I4:
4350                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4351                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4352                         break;
4353                 case OP_EXPAND_R4:
4354                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4355                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4356                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4357                         break;
4358                 case OP_EXPAND_R8:
4359                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4360                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4361                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4362                         break;
4363 #endif
4364                 case OP_LIVERANGE_START: {
4365                         if (cfg->verbose_level > 1)
4366                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4367                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4368                         break;
4369                 }
4370                 case OP_LIVERANGE_END: {
4371                         if (cfg->verbose_level > 1)
4372                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4373                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4374                         break;
4375                 }
4376                 default:
4377                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
4378                         g_assert_not_reached ();
4379                 }
4380
4381                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
4382                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4383                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4384                         g_assert_not_reached ();
4385                 }
4386                
4387                 cpos += max_len;
4388         }
4389
4390         cfg->code_len = code - cfg->native_code;
4391 }
4392
4393 #endif /* DISABLE_JIT */
4394
4395 void
4396 mono_arch_register_lowlevel_calls (void)
4397 {
4398 }
4399
4400 void
4401 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4402 {
4403         MonoJumpInfo *patch_info;
4404         gboolean compile_aot = !run_cctors;
4405
4406         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4407                 unsigned char *ip = patch_info->ip.i + code;
4408                 const unsigned char *target;
4409
4410                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4411
4412                 if (compile_aot) {
4413                         switch (patch_info->type) {
4414                         case MONO_PATCH_INFO_BB:
4415                         case MONO_PATCH_INFO_LABEL:
4416                                 break;
4417                         default:
4418                                 /* No need to patch these */
4419                                 continue;
4420                         }
4421                 }
4422
4423                 switch (patch_info->type) {
4424                 case MONO_PATCH_INFO_IP:
4425                         *((gconstpointer *)(ip)) = target;
4426                         break;
4427                 case MONO_PATCH_INFO_CLASS_INIT: {
4428                         guint8 *code = ip;
4429                         /* Might already been changed to a nop */
4430                         x86_call_code (code, 0);
4431                         x86_patch (ip, target);
4432                         break;
4433                 }
4434                 case MONO_PATCH_INFO_ABS:
4435                 case MONO_PATCH_INFO_METHOD:
4436                 case MONO_PATCH_INFO_METHOD_JUMP:
4437                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4438                 case MONO_PATCH_INFO_BB:
4439                 case MONO_PATCH_INFO_LABEL:
4440                 case MONO_PATCH_INFO_RGCTX_FETCH:
4441                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
4442                 case MONO_PATCH_INFO_MONITOR_ENTER:
4443                 case MONO_PATCH_INFO_MONITOR_EXIT:
4444                         x86_patch (ip, target);
4445                         break;
4446                 case MONO_PATCH_INFO_NONE:
4447                         break;
4448                 default: {
4449                         guint32 offset = mono_arch_get_patch_offset (ip);
4450                         *((gconstpointer *)(ip + offset)) = target;
4451                         break;
4452                 }
4453                 }
4454         }
4455 }
4456
4457 guint8 *
4458 mono_arch_emit_prolog (MonoCompile *cfg)
4459 {
4460         MonoMethod *method = cfg->method;
4461         MonoBasicBlock *bb;
4462         MonoMethodSignature *sig;
4463         MonoInst *inst;
4464         int alloc_size, pos, max_offset, i, cfa_offset;
4465         guint8 *code;
4466         gboolean need_stack_frame;
4467
4468         cfg->code_size = MAX (mono_method_get_header (method)->code_size * 4, 10240);
4469
4470         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4471                 cfg->code_size += 512;
4472
4473         code = cfg->native_code = g_malloc (cfg->code_size);
4474
4475         /* Offset between RSP and the CFA */
4476         cfa_offset = 0;
4477
4478         // CFA = sp + 4
4479         cfa_offset = sizeof (gpointer);
4480         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
4481         // IP saved at CFA - 4
4482         /* There is no IP reg on x86 */
4483         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
4484
4485         need_stack_frame = needs_stack_frame (cfg);
4486
4487         if (need_stack_frame) {
4488                 x86_push_reg (code, X86_EBP);
4489                 cfa_offset += sizeof (gpointer);
4490                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4491                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
4492                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
4493                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
4494         }
4495
4496         alloc_size = cfg->stack_offset;
4497         pos = 0;
4498
4499         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4500                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
4501                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
4502                         guint8 *buf, *no_domain_branch;
4503
4504                         code = mono_x86_emit_tls_get (code, X86_EAX, appdomain_tls_offset);
4505                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
4506                         no_domain_branch = code;
4507                         x86_branch8 (code, X86_CC_NE, 0, 0);
4508                         code = mono_x86_emit_tls_get ( code, X86_EAX, lmf_tls_offset);
4509                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
4510                         buf = code;
4511                         x86_branch8 (code, X86_CC_NE, 0, 0);
4512                         x86_patch (no_domain_branch, code);
4513                         x86_push_imm (code, cfg->domain);
4514                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4515                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4516                         x86_patch (buf, code);
4517 #ifdef PLATFORM_WIN32
4518                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4519                         /* FIXME: Add a separate key for LMF to avoid this */
4520                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4521 #endif
4522                 }
4523                 else {
4524                         g_assert (!cfg->compile_aot);
4525                         x86_push_imm (code, cfg->domain);
4526                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4527                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4528                 }
4529         }
4530
4531         if (method->save_lmf) {
4532                 pos += sizeof (MonoLMF);
4533
4534                 if (cfg->compile_aot)
4535                         cfg->disable_aot = TRUE;
4536
4537                 /* save the current IP */
4538                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4539                 x86_push_imm_template (code);
4540                 cfa_offset += sizeof (gpointer);
4541
4542                 /* save all caller saved regs */
4543                 x86_push_reg (code, X86_EBP);
4544                 cfa_offset += sizeof (gpointer);
4545                 x86_push_reg (code, X86_ESI);
4546                 cfa_offset += sizeof (gpointer);
4547                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4548                 x86_push_reg (code, X86_EDI);
4549                 cfa_offset += sizeof (gpointer);
4550                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4551                 x86_push_reg (code, X86_EBX);
4552                 cfa_offset += sizeof (gpointer);
4553                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4554
4555                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4556                         /*
4557                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4558                          * through the mono_lmf_addr TLS variable.
4559                          */
4560                         /* %eax = previous_lmf */
4561                         x86_prefix (code, X86_GS_PREFIX);
4562                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
4563                         /* skip esp + method_info + lmf */
4564                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
4565                         /* push previous_lmf */
4566                         x86_push_reg (code, X86_EAX);
4567                         /* new lmf = ESP */
4568                         x86_prefix (code, X86_GS_PREFIX);
4569                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
4570                 } else {
4571                         /* get the address of lmf for the current thread */
4572                         /* 
4573                          * This is performance critical so we try to use some tricks to make
4574                          * it fast.
4575                          */                                                                        
4576
4577                         if (lmf_addr_tls_offset != -1) {
4578                                 /* Load lmf quicky using the GS register */
4579                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
4580 #ifdef PLATFORM_WIN32
4581                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4582                                 /* FIXME: Add a separate key for LMF to avoid this */
4583                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4584 #endif
4585                         } else {
4586                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
4587                         }
4588
4589                         /* Skip esp + method info */
4590                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
4591
4592                         /* push lmf */
4593                         x86_push_reg (code, X86_EAX); 
4594                         /* push *lfm (previous_lmf) */
4595                         x86_push_membase (code, X86_EAX, 0);
4596                         /* *(lmf) = ESP */
4597                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
4598                 }
4599         } else {
4600
4601                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4602                         x86_push_reg (code, X86_EBX);
4603                         pos += 4;
4604                         cfa_offset += sizeof (gpointer);
4605                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4606                 }
4607
4608                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4609                         x86_push_reg (code, X86_EDI);
4610                         pos += 4;
4611                         cfa_offset += sizeof (gpointer);
4612                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4613                 }
4614
4615                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4616                         x86_push_reg (code, X86_ESI);
4617                         pos += 4;
4618                         cfa_offset += sizeof (gpointer);
4619                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4620                 }
4621         }
4622
4623         alloc_size -= pos;
4624
4625         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
4626         if (mono_do_x86_stack_align && need_stack_frame) {
4627                 int tot = alloc_size + pos + 4; /* ret ip */
4628                 if (need_stack_frame)
4629                         tot += 4; /* ebp */
4630                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
4631                 if (tot)
4632                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
4633         }
4634
4635         if (alloc_size) {
4636                 /* See mono_emit_stack_alloc */
4637 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4638                 guint32 remaining_size = alloc_size;
4639                 while (remaining_size >= 0x1000) {
4640                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
4641                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
4642                         remaining_size -= 0x1000;
4643                 }
4644                 if (remaining_size)
4645                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
4646 #else
4647                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4648 #endif
4649
4650                 g_assert (need_stack_frame);
4651         }
4652
4653         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
4654                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
4655                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
4656         }
4657
4658 #if DEBUG_STACK_ALIGNMENT
4659         /* check the stack is aligned */
4660         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
4661                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
4662                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
4663                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4664                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4665                 x86_breakpoint (code);
4666         }
4667 #endif
4668
4669         /* compute max_offset in order to use short forward jumps */
4670         max_offset = 0;
4671         if (cfg->opt & MONO_OPT_BRANCH) {
4672                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4673                         MonoInst *ins;
4674                         bb->max_offset = max_offset;
4675
4676                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4677                                 max_offset += 6;
4678                         /* max alignment for loops */
4679                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4680                                 max_offset += LOOP_ALIGNMENT;
4681
4682                         MONO_BB_FOR_EACH_INS (bb, ins) {
4683                                 if (ins->opcode == OP_LABEL)
4684                                         ins->inst_c1 = max_offset;
4685                                 
4686                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4687                         }
4688                 }
4689         }
4690
4691         /* store runtime generic context */
4692         if (cfg->rgctx_var) {
4693                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4694
4695                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4696         }
4697
4698         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4699                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4700
4701         /* load arguments allocated to register from the stack */
4702         sig = mono_method_signature (method);
4703         pos = 0;
4704
4705         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4706                 inst = cfg->args [pos];
4707                 if (inst->opcode == OP_REGVAR) {
4708                         g_assert (need_stack_frame);
4709                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
4710                         if (cfg->verbose_level > 2)
4711                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4712                 }
4713                 pos++;
4714         }
4715
4716         cfg->code_len = code - cfg->native_code;
4717
4718         g_assert (cfg->code_len < cfg->code_size);
4719
4720         return code;
4721 }
4722
4723 void
4724 mono_arch_emit_epilog (MonoCompile *cfg)
4725 {
4726         MonoMethod *method = cfg->method;
4727         MonoMethodSignature *sig = mono_method_signature (method);
4728         int quad, pos;
4729         guint32 stack_to_pop;
4730         guint8 *code;
4731         int max_epilog_size = 16;
4732         CallInfo *cinfo;
4733         gboolean need_stack_frame = needs_stack_frame (cfg);
4734
4735         if (cfg->method->save_lmf)
4736                 max_epilog_size += 128;
4737
4738         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4739                 cfg->code_size *= 2;
4740                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4741                 mono_jit_stats.code_reallocs++;
4742         }
4743
4744         code = cfg->native_code + cfg->code_len;
4745
4746         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4747                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4748
4749         /* the code restoring the registers must be kept in sync with OP_JMP */
4750         pos = 0;
4751         
4752         if (method->save_lmf) {
4753                 gint32 prev_lmf_reg;
4754                 gint32 lmf_offset = -sizeof (MonoLMF);
4755
4756                 /* check if we need to restore protection of the stack after a stack overflow */
4757                 if (mono_get_jit_tls_offset () != -1) {
4758                         guint8 *patch;
4759                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
4760                         /* we load the value in a separate instruction: this mechanism may be
4761                          * used later as a safer way to do thread interruption
4762                          */
4763                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
4764                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4765                         patch = code;
4766                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
4767                         /* note that the call trampoline will preserve eax/edx */
4768                         x86_call_reg (code, X86_ECX);
4769                         x86_patch (patch, code);
4770                 } else {
4771                         /* FIXME: maybe save the jit tls in the prolog */
4772                 }
4773                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4774                         /*
4775                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4776                          * through the mono_lmf_addr TLS variable.
4777                          */
4778                         /* reg = previous_lmf */
4779                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4780
4781                         /* lmf = previous_lmf */
4782                         x86_prefix (code, X86_GS_PREFIX);
4783                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
4784                 } else {
4785                         /* Find a spare register */
4786                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
4787                         case MONO_TYPE_I8:
4788                         case MONO_TYPE_U8:
4789                                 prev_lmf_reg = X86_EDI;
4790                                 cfg->used_int_regs |= (1 << X86_EDI);
4791                                 break;
4792                         default:
4793                                 prev_lmf_reg = X86_EDX;
4794                                 break;
4795                         }
4796
4797                         /* reg = previous_lmf */
4798                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4799
4800                         /* ecx = lmf */
4801                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
4802
4803                         /* *(lmf) = previous_lmf */
4804                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
4805                 }
4806
4807                 /* restore caller saved regs */
4808                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4809                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
4810                 }
4811
4812                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4813                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
4814                 }
4815                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4816                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
4817                 }
4818
4819                 /* EBP is restored by LEAVE */
4820         } else {
4821                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4822                         pos -= 4;
4823                 }
4824                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4825                         pos -= 4;
4826                 }
4827                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4828                         pos -= 4;
4829                 }
4830
4831                 if (pos) {
4832                         g_assert (need_stack_frame);
4833                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
4834                 }
4835
4836                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4837                         x86_pop_reg (code, X86_ESI);
4838                 }
4839                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4840                         x86_pop_reg (code, X86_EDI);
4841                 }
4842                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4843                         x86_pop_reg (code, X86_EBX);
4844                 }
4845         }
4846
4847         /* Load returned vtypes into registers if needed */
4848         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
4849         if (cinfo->ret.storage == ArgValuetypeInReg) {
4850                 for (quad = 0; quad < 2; quad ++) {
4851                         switch (cinfo->ret.pair_storage [quad]) {
4852                         case ArgInIReg:
4853                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
4854                                 break;
4855                         case ArgOnFloatFpStack:
4856                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
4857                                 break;
4858                         case ArgOnDoubleFpStack:
4859                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
4860                                 break;
4861                         case ArgNone:
4862                                 break;
4863                         default:
4864                                 g_assert_not_reached ();
4865                         }
4866                 }
4867         }
4868
4869         if (need_stack_frame)
4870                 x86_leave (code);
4871
4872         if (CALLCONV_IS_STDCALL (sig)) {
4873                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
4874
4875                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
4876         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
4877                 stack_to_pop = 4;
4878         else
4879                 stack_to_pop = 0;
4880
4881         if (stack_to_pop) {
4882                 g_assert (need_stack_frame);
4883                 x86_ret_imm (code, stack_to_pop);
4884         } else {
4885                 x86_ret (code);
4886         }
4887
4888         cfg->code_len = code - cfg->native_code;
4889
4890         g_assert (cfg->code_len < cfg->code_size);
4891 }
4892
4893 void
4894 mono_arch_emit_exceptions (MonoCompile *cfg)
4895 {
4896         MonoJumpInfo *patch_info;
4897         int nthrows, i;
4898         guint8 *code;
4899         MonoClass *exc_classes [16];
4900         guint8 *exc_throw_start [16], *exc_throw_end [16];
4901         guint32 code_size;
4902         int exc_count = 0;
4903
4904         /* Compute needed space */
4905         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4906                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4907                         exc_count++;
4908         }
4909
4910         /* 
4911          * make sure we have enough space for exceptions
4912          * 16 is the size of two push_imm instructions and a call
4913          */
4914         if (cfg->compile_aot)
4915                 code_size = exc_count * 32;
4916         else
4917                 code_size = exc_count * 16;
4918
4919         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4920                 cfg->code_size *= 2;
4921                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4922                 mono_jit_stats.code_reallocs++;
4923         }
4924
4925         code = cfg->native_code + cfg->code_len;
4926
4927         nthrows = 0;
4928         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4929                 switch (patch_info->type) {
4930                 case MONO_PATCH_INFO_EXC: {
4931                         MonoClass *exc_class;
4932                         guint8 *buf, *buf2;
4933                         guint32 throw_ip;
4934
4935                         x86_patch (patch_info->ip.i + cfg->native_code, code);
4936
4937                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4938                         g_assert (exc_class);
4939                         throw_ip = patch_info->ip.i;
4940
4941                         /* Find a throw sequence for the same exception class */
4942                         for (i = 0; i < nthrows; ++i)
4943                                 if (exc_classes [i] == exc_class)
4944                                         break;
4945                         if (i < nthrows) {
4946                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
4947                                 x86_jump_code (code, exc_throw_start [i]);
4948                                 patch_info->type = MONO_PATCH_INFO_NONE;
4949                         }
4950                         else {
4951                                 guint32 size;
4952
4953                                 /* Compute size of code following the push <OFFSET> */
4954                                 size = 5 + 5;
4955
4956                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
4957
4958                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
4959                                         /* Use the shorter form */
4960                                         buf = buf2 = code;
4961                                         x86_push_imm (code, 0);
4962                                 }
4963                                 else {
4964                                         buf = code;
4965                                         x86_push_imm (code, 0xf0f0f0f0);
4966                                         buf2 = code;
4967                                 }
4968
4969                                 if (nthrows < 16) {
4970                                         exc_classes [nthrows] = exc_class;
4971                                         exc_throw_start [nthrows] = code;
4972                                 }
4973
4974                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
4975                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4976                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4977                                 patch_info->ip.i = code - cfg->native_code;
4978                                 x86_call_code (code, 0);
4979                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
4980                                 while (buf < buf2)
4981                                         x86_nop (buf);
4982
4983                                 if (nthrows < 16) {
4984                                         exc_throw_end [nthrows] = code;
4985                                         nthrows ++;
4986                                 }
4987                         }
4988                         break;
4989                 }
4990                 default:
4991                         /* do nothing */
4992                         break;
4993                 }
4994         }
4995
4996         cfg->code_len = code - cfg->native_code;
4997
4998         g_assert (cfg->code_len < cfg->code_size);
4999 }
5000
5001 void
5002 mono_arch_flush_icache (guint8 *code, gint size)
5003 {
5004         /* not needed */
5005 }
5006
5007 void
5008 mono_arch_flush_register_windows (void)
5009 {
5010 }
5011
5012 gboolean 
5013 mono_arch_is_inst_imm (gint64 imm)
5014 {
5015         return TRUE;
5016 }
5017
5018 /*
5019  * Support for fast access to the thread-local lmf structure using the GS
5020  * segment register on NPTL + kernel 2.6.x.
5021  */
5022
5023 static gboolean tls_offset_inited = FALSE;
5024
5025 void
5026 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5027 {
5028         if (!tls_offset_inited) {
5029                 if (!getenv ("MONO_NO_TLS")) {
5030 #ifdef PLATFORM_WIN32
5031                         /* 
5032                          * We need to init this multiple times, since when we are first called, the key might not
5033                          * be initialized yet.
5034                          */
5035                         appdomain_tls_offset = mono_domain_get_tls_key ();
5036                         lmf_tls_offset = mono_get_jit_tls_key ();
5037
5038                         /* Only 64 tls entries can be accessed using inline code */
5039                         if (appdomain_tls_offset >= 64)
5040                                 appdomain_tls_offset = -1;
5041                         if (lmf_tls_offset >= 64)
5042                                 lmf_tls_offset = -1;
5043 #else
5044 #if MONO_XEN_OPT
5045                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5046 #endif
5047                         tls_offset_inited = TRUE;
5048                         appdomain_tls_offset = mono_domain_get_tls_offset ();
5049                         lmf_tls_offset = mono_get_lmf_tls_offset ();
5050                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5051 #endif
5052                 }
5053         }               
5054 }
5055
5056 void
5057 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5058 {
5059 }
5060
5061 #ifdef MONO_ARCH_HAVE_IMT
5062
5063 // Linear handler, the bsearch head compare is shorter
5064 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5065 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5066 //        x86_patch(ins,target)
5067 //[1 + 5] x86_jump_mem(inst,mem)
5068
5069 #define CMP_SIZE 6
5070 #define BR_SMALL_SIZE 2
5071 #define BR_LARGE_SIZE 5
5072 #define JUMP_IMM_SIZE 6
5073 #define ENABLE_WRONG_METHOD_CHECK 0
5074
5075 static int
5076 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5077 {
5078         int i, distance = 0;
5079         for (i = start; i < target; ++i)
5080                 distance += imt_entries [i]->chunk_size;
5081         return distance;
5082 }
5083
5084 /*
5085  * LOCKING: called with the domain lock held
5086  */
5087 gpointer
5088 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5089         gpointer fail_tramp)
5090 {
5091         int i;
5092         int size = 0;
5093         guint8 *code, *start;
5094
5095         for (i = 0; i < count; ++i) {
5096                 MonoIMTCheckItem *item = imt_entries [i];
5097                 if (item->is_equals) {
5098                         if (item->check_target_idx) {
5099                                 if (!item->compare_done)
5100                                         item->chunk_size += CMP_SIZE;
5101                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5102                         } else {
5103                                 if (fail_tramp) {
5104                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5105                                 } else {
5106                                         item->chunk_size += JUMP_IMM_SIZE;
5107 #if ENABLE_WRONG_METHOD_CHECK
5108                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5109 #endif
5110                                 }
5111                         }
5112                 } else {
5113                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5114                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5115                 }
5116                 size += item->chunk_size;
5117         }
5118         if (fail_tramp)
5119                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5120         else
5121                 code = mono_domain_code_reserve (domain, size);
5122         start = code;
5123         for (i = 0; i < count; ++i) {
5124                 MonoIMTCheckItem *item = imt_entries [i];
5125                 item->code_target = code;
5126                 if (item->is_equals) {
5127                         if (item->check_target_idx) {
5128                                 if (!item->compare_done)
5129                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5130                                 item->jmp_code = code;
5131                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5132                                 if (item->has_target_code)
5133                                         x86_jump_code (code, item->value.target_code);
5134                                 else
5135                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5136                         } else {
5137                                 if (fail_tramp) {
5138                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5139                                         item->jmp_code = code;
5140                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5141                                         if (item->has_target_code)
5142                                                 x86_jump_code (code, item->value.target_code);
5143                                         else
5144                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5145                                         x86_patch (item->jmp_code, code);
5146                                         x86_jump_code (code, fail_tramp);
5147                                         item->jmp_code = NULL;
5148                                 } else {
5149                                         /* enable the commented code to assert on wrong method */
5150 #if ENABLE_WRONG_METHOD_CHECK
5151                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5152                                         item->jmp_code = code;
5153                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5154 #endif
5155                                         if (item->has_target_code)
5156                                                 x86_jump_code (code, item->value.target_code);
5157                                         else
5158                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5159 #if ENABLE_WRONG_METHOD_CHECK
5160                                         x86_patch (item->jmp_code, code);
5161                                         x86_breakpoint (code);
5162                                         item->jmp_code = NULL;
5163 #endif
5164                                 }
5165                         }
5166                 } else {
5167                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5168                         item->jmp_code = code;
5169                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5170                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5171                         else
5172                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5173                 }
5174         }
5175         /* patch the branches to get to the target items */
5176         for (i = 0; i < count; ++i) {
5177                 MonoIMTCheckItem *item = imt_entries [i];
5178                 if (item->jmp_code) {
5179                         if (item->check_target_idx) {
5180                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5181                         }
5182                 }
5183         }
5184
5185         if (!fail_tramp)
5186                 mono_stats.imt_thunks_size += code - start;
5187         g_assert (code - start <= size);
5188         return start;
5189 }
5190
5191 MonoMethod*
5192 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5193 {
5194         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5195 }
5196
5197 MonoObject*
5198 mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5199 {
5200         MonoMethodSignature *sig = mono_method_signature (method);
5201         CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5202         int this_argument_offset;
5203         MonoObject *this_argument;
5204
5205         /* 
5206          * this is the offset of the this arg from esp as saved at the start of 
5207          * mono_arch_create_trampoline_code () in tramp-x86.c.
5208          */
5209         this_argument_offset = 5;
5210         if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
5211                 this_argument_offset++;
5212
5213         this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
5214
5215         g_free (cinfo);
5216         return this_argument;
5217 }
5218 #endif
5219
5220 MonoVTable*
5221 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5222 {
5223         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5224 }
5225
5226 MonoInst*
5227 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5228 {
5229         MonoInst *ins = NULL;
5230         int opcode = 0;
5231
5232         if (cmethod->klass == mono_defaults.math_class) {
5233                 if (strcmp (cmethod->name, "Sin") == 0) {
5234                         opcode = OP_SIN;
5235                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5236                         opcode = OP_COS;
5237                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5238                         opcode = OP_TAN;
5239                 } else if (strcmp (cmethod->name, "Atan") == 0) {
5240                         opcode = OP_ATAN;
5241                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5242                         opcode = OP_SQRT;
5243                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5244                         opcode = OP_ABS;
5245                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
5246                         opcode = OP_ROUND;
5247                 }
5248                 
5249                 if (opcode) {
5250                         MONO_INST_NEW (cfg, ins, opcode);
5251                         ins->type = STACK_R8;
5252                         ins->dreg = mono_alloc_freg (cfg);
5253                         ins->sreg1 = args [0]->dreg;
5254                         MONO_ADD_INS (cfg->cbb, ins);
5255                 }
5256
5257                 if (cfg->opt & MONO_OPT_CMOV) {
5258                         int opcode = 0;
5259
5260                         if (strcmp (cmethod->name, "Min") == 0) {
5261                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5262                                         opcode = OP_IMIN;
5263                         } else if (strcmp (cmethod->name, "Max") == 0) {
5264                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5265                                         opcode = OP_IMAX;
5266                         }               
5267
5268                         if (opcode) {
5269                                 MONO_INST_NEW (cfg, ins, opcode);
5270                                 ins->type = STACK_I4;
5271                                 ins->dreg = mono_alloc_ireg (cfg);
5272                                 ins->sreg1 = args [0]->dreg;
5273                                 ins->sreg2 = args [1]->dreg;
5274                                 MONO_ADD_INS (cfg->cbb, ins);
5275                         }
5276                 }
5277
5278 #if 0
5279                 /* OP_FREM is not IEEE compatible */
5280                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
5281                         MONO_INST_NEW (cfg, ins, OP_FREM);
5282                         ins->inst_i0 = args [0];
5283                         ins->inst_i1 = args [1];
5284                 }
5285 #endif
5286         }
5287
5288         return ins;
5289 }
5290
5291 gboolean
5292 mono_arch_print_tree (MonoInst *tree, int arity)
5293 {
5294         return 0;
5295 }
5296
5297 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5298 {
5299         MonoInst* ins;
5300
5301         return NULL;
5302
5303         if (appdomain_tls_offset == -1)
5304                 return NULL;
5305
5306         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5307         ins->inst_offset = appdomain_tls_offset;
5308         return ins;
5309 }
5310
5311 guint32
5312 mono_arch_get_patch_offset (guint8 *code)
5313 {
5314         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
5315                 return 2;
5316         else if ((code [0] == 0xba))
5317                 return 1;
5318         else if ((code [0] == 0x68))
5319                 /* push IMM */
5320                 return 1;
5321         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
5322                 /* push <OFFSET>(<REG>) */
5323                 return 2;
5324         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
5325                 /* call *<OFFSET>(<REG>) */
5326                 return 2;
5327         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
5328                 /* fldl <ADDR> */
5329                 return 2;
5330         else if ((code [0] == 0x58) && (code [1] == 0x05))
5331                 /* pop %eax; add <OFFSET>, %eax */
5332                 return 2;
5333         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
5334                 /* pop <REG>; add <OFFSET>, <REG> */
5335                 return 3;
5336         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
5337                 /* mov <REG>, imm */
5338                 return 1;
5339         else {
5340                 g_assert_not_reached ();
5341                 return -1;
5342         }
5343 }
5344
5345 /**
5346  * mono_breakpoint_clean_code:
5347  *
5348  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
5349  * breakpoints in the original code, they are removed in the copy.
5350  *
5351  * Returns TRUE if no sw breakpoint was present.
5352  */
5353 gboolean
5354 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
5355 {
5356         int i;
5357         gboolean can_write = TRUE;
5358         /*
5359          * If method_start is non-NULL we need to perform bound checks, since we access memory
5360          * at code - offset we could go before the start of the method and end up in a different
5361          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
5362          * instead.
5363          */
5364         if (!method_start || code - offset >= method_start) {
5365                 memcpy (buf, code - offset, size);
5366         } else {
5367                 int diff = code - method_start;
5368                 memset (buf, 0, size);
5369                 memcpy (buf + offset - diff, method_start, diff + size - offset);
5370         }
5371         code -= offset;
5372         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
5373                 int idx = mono_breakpoint_info_index [i];
5374                 guint8 *ptr;
5375                 if (idx < 1)
5376                         continue;
5377                 ptr = mono_breakpoint_info [idx].address;
5378                 if (ptr >= code && ptr < code + size) {
5379                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
5380                         can_write = FALSE;
5381                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
5382                         buf [ptr - code] = saved_byte;
5383                 }
5384         }
5385         return can_write;
5386 }
5387
5388 gpointer
5389 mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
5390 {
5391         guint8 buf [8];
5392         guint8 reg = 0;
5393         gint32 disp = 0;
5394
5395         mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
5396         code = buf + 8;
5397
5398         *displacement = 0;
5399
5400         code -= 6;
5401
5402         /* 
5403          * A given byte sequence can match more than case here, so we have to be
5404          * really careful about the ordering of the cases. Longer sequences
5405          * come first.
5406          * There are two types of calls:
5407          * - direct calls: 0xff address_byte 8/32 bits displacement
5408          * - indirect calls: nop nop nop <call>
5409          * The nops make sure we don't confuse the instruction preceeding an indirect
5410          * call with a direct call.
5411          */
5412         if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
5413                 reg = code [4] & 0x07;
5414                 disp = (signed char)code [5];
5415         } else if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
5416                 reg = code [1] & 0x07;
5417                 disp = *((gint32*)(code + 2));
5418         } else if ((code [1] == 0xe8)) {
5419                         return NULL;
5420         } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
5421                 /*
5422                  * This is a interface call
5423                  * 8b 40 30   mov    0x30(%eax),%eax
5424                  * ff 10      call   *(%eax)
5425                  */
5426                 disp = 0;
5427                 reg = code [5] & 0x07;
5428         }
5429         else
5430                 return NULL;
5431
5432         *displacement = disp;
5433         return (gpointer)regs [reg];
5434 }
5435
5436 /*
5437  * mono_x86_get_this_arg_offset:
5438  *
5439  *   Return the offset of the stack location where this is passed during a virtual
5440  * call.
5441  */
5442 guint32
5443 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
5444 {
5445         CallInfo *cinfo = NULL;
5446         int offset;
5447
5448         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5449                 cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5450
5451                 offset = cinfo->args [0].offset;
5452         } else {
5453                 offset = 0;
5454         }
5455
5456         return offset;
5457 }
5458
5459 gpointer
5460 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
5461                 mgreg_t *regs, guint8 *code)
5462 {
5463         guint32 esp = regs [X86_ESP];
5464         CallInfo *cinfo = NULL;
5465         gpointer res;
5466         int offset;
5467
5468         /* 
5469          * Avoid expensive calls to get_generic_context_from_code () + get_call_info 
5470          * if possible.
5471          */
5472         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5473                 if (!gsctx && code)
5474                         gsctx = mono_get_generic_context_from_code (code);
5475                 cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5476
5477                 offset = cinfo->args [0].offset;
5478         } else {
5479                 offset = 0;
5480         }
5481
5482         /*
5483          * The stack looks like:
5484          * <other args>
5485          * <this=delegate>
5486          * <possible vtype return address>
5487          * <return addr>
5488          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
5489          */
5490         res = (((MonoObject**)esp) [5 + (offset / 4)]);
5491         if (cinfo)
5492                 g_free (cinfo);
5493         return res;
5494 }
5495
5496 #define MAX_ARCH_DELEGATE_PARAMS 10
5497
5498 gpointer
5499 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5500 {
5501         guint8 *code, *start;
5502
5503         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
5504                 return NULL;
5505
5506         /* FIXME: Support more cases */
5507         if (MONO_TYPE_ISSTRUCT (sig->ret))
5508                 return NULL;
5509
5510         /*
5511          * The stack contains:
5512          * <delegate>
5513          * <return addr>
5514          */
5515
5516         if (has_target) {
5517                 static guint8* cached = NULL;
5518                 if (cached)
5519                         return cached;
5520                 
5521                 start = code = mono_global_codeman_reserve (64);
5522
5523                 /* Replace the this argument with the target */
5524                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
5525                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
5526                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
5527                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5528
5529                 g_assert ((code - start) < 64);
5530
5531                 mono_debug_add_delegate_trampoline (start, code - start);
5532
5533                 mono_memory_barrier ();
5534
5535                 cached = start;
5536         } else {
5537                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
5538                 int i = 0;
5539                 /* 8 for mov_reg and jump, plus 8 for each parameter */
5540                 int code_reserve = 8 + (sig->param_count * 8);
5541
5542                 for (i = 0; i < sig->param_count; ++i)
5543                         if (!mono_is_regsize_var (sig->params [i]))
5544                                 return NULL;
5545
5546                 code = cache [sig->param_count];
5547                 if (code)
5548                         return code;
5549
5550                 /*
5551                  * The stack contains:
5552                  * <args in reverse order>
5553                  * <delegate>
5554                  * <return addr>
5555                  *
5556                  * and we need:
5557                  * <args in reverse order>
5558                  * <return addr>
5559                  * 
5560                  * without unbalancing the stack.
5561                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
5562                  * and leaving original spot of first arg as placeholder in stack so
5563                  * when callee pops stack everything works.
5564                  */
5565
5566                 start = code = mono_global_codeman_reserve (code_reserve);
5567
5568                 /* store delegate for access to method_ptr */
5569                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
5570
5571                 /* move args up */
5572                 for (i = 0; i < sig->param_count; ++i) {
5573                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
5574                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
5575                 }
5576
5577                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5578
5579                 g_assert ((code - start) < code_reserve);
5580
5581                 mono_debug_add_delegate_trampoline (start, code - start);
5582
5583                 mono_memory_barrier ();
5584
5585                 cache [sig->param_count] = start;
5586         }
5587
5588         return start;
5589 }
5590
5591 gpointer
5592 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5593 {
5594         switch (reg) {
5595         case X86_EAX: return (gpointer)ctx->eax;
5596         case X86_EBX: return (gpointer)ctx->ebx;
5597         case X86_ECX: return (gpointer)ctx->ecx;
5598         case X86_EDX: return (gpointer)ctx->edx;
5599         case X86_ESP: return (gpointer)ctx->esp;
5600         case X86_EBP: return (gpointer)ctx->ebp;
5601         case X86_ESI: return (gpointer)ctx->esi;
5602         case X86_EDI: return (gpointer)ctx->edi;
5603         default: g_assert_not_reached ();
5604         }
5605 }
5606
5607 #ifdef MONO_ARCH_SIMD_INTRINSICS
5608
5609 static MonoInst*
5610 get_float_to_x_spill_area (MonoCompile *cfg)
5611 {
5612         if (!cfg->fconv_to_r8_x_var) {
5613                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5614                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
5615         }       
5616         return cfg->fconv_to_r8_x_var;
5617 }
5618
5619 /*
5620  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
5621  */
5622 void
5623 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5624 {
5625         MonoInst *fconv;
5626         int dreg, src_opcode;
5627
5628         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
5629                 return;
5630
5631         switch (src_opcode = ins->opcode) {
5632         case OP_FCONV_TO_I1:
5633         case OP_FCONV_TO_U1:
5634         case OP_FCONV_TO_I2:
5635         case OP_FCONV_TO_U2:
5636         case OP_FCONV_TO_I4:
5637         case OP_FCONV_TO_I:
5638                 break;
5639         default:
5640                 return;
5641         }
5642
5643         /* dreg is the IREG and sreg1 is the FREG */
5644         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
5645         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
5646         fconv->sreg1 = ins->sreg1;
5647         fconv->dreg = mono_alloc_ireg (cfg);
5648         fconv->type = STACK_VTYPE;
5649         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
5650
5651         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
5652
5653         dreg = ins->dreg;
5654         NULLIFY_INS (ins);
5655         ins->opcode = OP_XCONV_R8_TO_I4;
5656
5657         ins->klass = mono_defaults.int32_class;
5658         ins->sreg1 = fconv->dreg;
5659         ins->dreg = dreg;
5660         ins->type = STACK_I4;
5661         ins->backend.source_opcode = src_opcode;
5662 }
5663
5664 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
5665
5666 void
5667 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
5668 {
5669         MonoInst *ins;
5670         int vreg;
5671
5672         if (long_ins->opcode == OP_LNEG) {
5673                 ins = long_ins;
5674                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
5675                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
5676                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
5677                 NULLIFY_INS (ins);
5678                 return;
5679         }
5680
5681 #ifdef MONO_ARCH_SIMD_INTRINSICS
5682
5683         if (!(cfg->opt & MONO_OPT_SIMD))
5684                 return;
5685         
5686         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
5687         switch (long_ins->opcode) {
5688         case OP_EXTRACT_I8:
5689                 vreg = long_ins->sreg1;
5690         
5691                 if (long_ins->inst_c0) {
5692                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5693                         ins->klass = long_ins->klass;
5694                         ins->sreg1 = long_ins->sreg1;
5695                         ins->inst_c0 = 2;
5696                         ins->type = STACK_VTYPE;
5697                         ins->dreg = vreg = alloc_ireg (cfg);
5698                         MONO_ADD_INS (cfg->cbb, ins);
5699                 }
5700         
5701                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
5702                 ins->klass = mono_defaults.int32_class;
5703                 ins->sreg1 = vreg;
5704                 ins->type = STACK_I4;
5705                 ins->dreg = long_ins->dreg + 1;
5706                 MONO_ADD_INS (cfg->cbb, ins);
5707         
5708                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5709                 ins->klass = long_ins->klass;
5710                 ins->sreg1 = long_ins->sreg1;
5711                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
5712                 ins->type = STACK_VTYPE;
5713                 ins->dreg = vreg = alloc_ireg (cfg);
5714                 MONO_ADD_INS (cfg->cbb, ins);
5715         
5716                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
5717                 ins->klass = mono_defaults.int32_class;
5718                 ins->sreg1 = vreg;
5719                 ins->type = STACK_I4;
5720                 ins->dreg = long_ins->dreg + 2;
5721                 MONO_ADD_INS (cfg->cbb, ins);
5722         
5723                 long_ins->opcode = OP_NOP;
5724                 break;
5725         case OP_INSERTX_I8_SLOW:
5726                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5727                 ins->dreg = long_ins->dreg;
5728                 ins->sreg1 = long_ins->dreg;
5729                 ins->sreg2 = long_ins->sreg2 + 1;
5730                 ins->inst_c0 = long_ins->inst_c0 * 2;
5731                 MONO_ADD_INS (cfg->cbb, ins);
5732
5733                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5734                 ins->dreg = long_ins->dreg;
5735                 ins->sreg1 = long_ins->dreg;
5736                 ins->sreg2 = long_ins->sreg2 + 2;
5737                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
5738                 MONO_ADD_INS (cfg->cbb, ins);
5739
5740                 long_ins->opcode = OP_NOP;
5741                 break;
5742         case OP_EXPAND_I8:
5743                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
5744                 ins->dreg = long_ins->dreg;
5745                 ins->sreg1 = long_ins->sreg1 + 1;
5746                 ins->klass = long_ins->klass;
5747                 ins->type = STACK_VTYPE;
5748                 MONO_ADD_INS (cfg->cbb, ins);
5749
5750                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
5751                 ins->dreg = long_ins->dreg;
5752                 ins->sreg1 = long_ins->dreg;
5753                 ins->sreg2 = long_ins->sreg1 + 2;
5754                 ins->inst_c0 = 1;
5755                 ins->klass = long_ins->klass;
5756                 ins->type = STACK_VTYPE;
5757                 MONO_ADD_INS (cfg->cbb, ins);
5758
5759                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5760                 ins->dreg = long_ins->dreg;
5761                 ins->sreg1 = long_ins->dreg;;
5762                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
5763                 ins->klass = long_ins->klass;
5764                 ins->type = STACK_VTYPE;
5765                 MONO_ADD_INS (cfg->cbb, ins);
5766
5767                 long_ins->opcode = OP_NOP;
5768                 break;
5769         }
5770 #endif /* MONO_ARCH_SIMD_INTRINSICS */
5771 }
5772
5773 #if __APPLE__
5774 #define DBG_SIGNAL SIGBUS
5775 #else
5776 #define DBG_SIGNAL SIGSEGV
5777 #endif
5778
5779 /* Soft Debug support */
5780 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5781
5782 /*
5783  * mono_arch_set_breakpoint:
5784  *
5785  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
5786  * The location should contain code emitted by OP_SEQ_POINT.
5787  */
5788 void
5789 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5790 {
5791         guint8 *code = ip;
5792
5793         /* 
5794          * In production, we will use int3 (has to fix the size in the md 
5795          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
5796          * instead.
5797          */
5798         g_assert (code [0] == 0x90);
5799         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
5800 }
5801
5802 /*
5803  * mono_arch_clear_breakpoint:
5804  *
5805  *   Clear the breakpoint at IP.
5806  */
5807 void
5808 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5809 {
5810         guint8 *code = ip;
5811         int i;
5812
5813         for (i = 0; i < 6; ++i)
5814                 x86_nop (code);
5815 }
5816         
5817 /*
5818  * mono_arch_start_single_stepping:
5819  *
5820  *   Start single stepping.
5821  */
5822 void
5823 mono_arch_start_single_stepping (void)
5824 {
5825         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5826 }
5827         
5828 /*
5829  * mono_arch_stop_single_stepping:
5830  *
5831  *   Stop single stepping.
5832  */
5833 void
5834 mono_arch_stop_single_stepping (void)
5835 {
5836         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5837 }
5838
5839 /*
5840  * mono_arch_is_single_step_event:
5841  *
5842  *   Return whenever the machine state in SIGCTX corresponds to a single
5843  * step event.
5844  */
5845 gboolean
5846 mono_arch_is_single_step_event (void *info, void *sigctx)
5847 {
5848 #ifdef PLATFORM_WIN32
5849         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;
5850         return FALSE;
5851 #else
5852         siginfo_t* sinfo = (siginfo_t*) info;
5853         /* Sometimes the address is off by 4 */
5854         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
5855                 return TRUE;
5856         else
5857                 return FALSE;
5858 #endif
5859 }
5860
5861 gboolean
5862 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5863 {
5864 #ifdef PLATFORM_WIN32
5865         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;
5866         return FALSE;
5867 #else
5868         siginfo_t* sinfo = (siginfo_t*)info;
5869         /* Sometimes the address is off by 4 */
5870         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
5871                 return TRUE;
5872         else
5873                 return FALSE;
5874 #endif
5875 }
5876
5877 /*
5878  * mono_arch_get_ip_for_breakpoint:
5879  *
5880  *   See mini-amd64.c for docs.
5881  */
5882 guint8*
5883 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
5884 {
5885         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5886
5887         return ip;
5888 }
5889
5890 #define BREAKPOINT_SIZE 6
5891
5892 /*
5893  * mono_arch_get_ip_for_single_step:
5894  *
5895  *   See mini-amd64.c for docs.
5896  */
5897 guint8*
5898 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
5899 {
5900         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5901
5902         /* Size of x86_alu_reg_imm */
5903         ip += 6;
5904
5905         return ip;
5906 }
5907
5908 /*
5909  * mono_arch_skip_breakpoint:
5910  *
5911  *   See mini-amd64.c for docs.
5912  */
5913 void
5914 mono_arch_skip_breakpoint (MonoContext *ctx)
5915 {
5916         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
5917 }
5918
5919 /*
5920  * mono_arch_skip_single_step:
5921  *
5922  *   See mini-amd64.c for docs.
5923  */
5924 void
5925 mono_arch_skip_single_step (MonoContext *ctx)
5926 {
5927         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
5928 }
5929
5930 /*
5931  * mono_arch_get_seq_point_info:
5932  *
5933  *   See mini-amd64.c for docs.
5934  */
5935 gpointer
5936 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5937 {
5938         NOT_IMPLEMENTED;
5939         return NULL;
5940 }
5941
5942 #endif
5943