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