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