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