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