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