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