Get rid of the old mono_arch_find_jit_info functions + defines as all platforms suppo...
[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                         /* Not needed on x86 */
3903                         break;
3904                 }
3905                 case OP_ATOMIC_ADD_I4: {
3906                         int dreg = ins->dreg;
3907
3908                         if (dreg == ins->inst_basereg) {
3909                                 x86_push_reg (code, ins->sreg2);
3910                                 dreg = ins->sreg2;
3911                         } 
3912                         
3913                         if (dreg != ins->sreg2)
3914                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
3915
3916                         x86_prefix (code, X86_LOCK_PREFIX);
3917                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3918
3919                         if (dreg != ins->dreg) {
3920                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3921                                 x86_pop_reg (code, dreg);
3922                         }
3923
3924                         break;
3925                 }
3926                 case OP_ATOMIC_ADD_NEW_I4: {
3927                         int dreg = ins->dreg;
3928
3929                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
3930                         if (ins->sreg2 == dreg) {
3931                                 if (dreg == X86_EBX) {
3932                                         dreg = X86_EDI;
3933                                         if (ins->inst_basereg == X86_EDI)
3934                                                 dreg = X86_ESI;
3935                                 } else {
3936                                         dreg = X86_EBX;
3937                                         if (ins->inst_basereg == X86_EBX)
3938                                                 dreg = X86_EDI;
3939                                 }
3940                         } else if (ins->inst_basereg == dreg) {
3941                                 if (dreg == X86_EBX) {
3942                                         dreg = X86_EDI;
3943                                         if (ins->sreg2 == X86_EDI)
3944                                                 dreg = X86_ESI;
3945                                 } else {
3946                                         dreg = X86_EBX;
3947                                         if (ins->sreg2 == X86_EBX)
3948                                                 dreg = X86_EDI;
3949                                 }
3950                         }
3951
3952                         if (dreg != ins->dreg) {
3953                                 x86_push_reg (code, dreg);
3954                         }
3955
3956                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
3957                         x86_prefix (code, X86_LOCK_PREFIX);
3958                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3959                         /* dreg contains the old value, add with sreg2 value */
3960                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
3961                         
3962                         if (ins->dreg != dreg) {
3963                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3964                                 x86_pop_reg (code, dreg);
3965                         }
3966
3967                         break;
3968                 }
3969                 case OP_ATOMIC_EXCHANGE_I4: {
3970                         guchar *br[2];
3971                         int sreg2 = ins->sreg2;
3972                         int breg = ins->inst_basereg;
3973
3974                         /* cmpxchg uses eax as comperand, need to make sure we can use it
3975                          * hack to overcome limits in x86 reg allocator 
3976                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
3977                          */
3978                         g_assert (ins->dreg == X86_EAX);
3979                         
3980                         /* We need the EAX reg for the cmpxchg */
3981                         if (ins->sreg2 == X86_EAX) {
3982                                 sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX;
3983                                 x86_push_reg (code, sreg2);
3984                                 x86_mov_reg_reg (code, sreg2, X86_EAX, 4);
3985                         }
3986
3987                         if (breg == X86_EAX) {
3988                                 breg = (sreg2 == X86_ESI) ? X86_EDI : X86_ESI;
3989                                 x86_push_reg (code, breg);
3990                                 x86_mov_reg_reg (code, breg, X86_EAX, 4);
3991                         }
3992
3993                         x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
3994
3995                         br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
3996                         x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3997                         br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
3998                         x86_patch (br [1], br [0]);
3999
4000                         if (breg != ins->inst_basereg)
4001                                 x86_pop_reg (code, breg);
4002
4003                         if (ins->sreg2 != sreg2)
4004                                 x86_pop_reg (code, sreg2);
4005
4006                         break;
4007                 }
4008                 case OP_ATOMIC_CAS_I4: {
4009                         g_assert (ins->dreg == X86_EAX);
4010                         g_assert (ins->sreg3 == X86_EAX);
4011                         g_assert (ins->sreg1 != X86_EAX);
4012                         g_assert (ins->sreg1 != ins->sreg2);
4013
4014                         x86_prefix (code, X86_LOCK_PREFIX);
4015                         x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
4016                         break;
4017                 }
4018 #ifdef HAVE_SGEN_GC
4019                 case OP_CARD_TABLE_WBARRIER: {
4020                         int ptr = ins->sreg1;
4021                         int value = ins->sreg2;
4022                         guchar *br;
4023                         int nursery_shift, card_table_shift;
4024                         gpointer card_table_mask;
4025                         size_t nursery_size;
4026                         gulong card_table = (gulong)mono_gc_get_card_table (&card_table_shift, &card_table_mask);
4027                         gulong nursery_start = (gulong)mono_gc_get_nursery (&nursery_shift, &nursery_size);
4028
4029                         /*
4030                          * We need one register we can clobber, we choose EDX and make sreg1
4031                          * fixed EAX to work around limitations in the local register allocator.
4032                          * sreg2 might get allocated to EDX, but that is not a problem since
4033                          * we use it before clobbering EDX.
4034                          */
4035                         g_assert (ins->sreg1 == X86_EAX);
4036
4037                         /*
4038                          * This is the code we produce:
4039                          *
4040                          *   edx = value
4041                          *   edx >>= nursery_shift
4042                          *   cmp edx, (nursery_start >> nursery_shift)
4043                          *   jne done
4044                          *   edx = ptr
4045                          *   edx >>= card_table_shift
4046                          *   card_table[edx] = 1
4047                          * done:
4048                          */
4049
4050                         if (value != X86_EDX)
4051                                 x86_mov_reg_reg (code, X86_EDX, value, 4);
4052                         x86_shift_reg_imm (code, X86_SHR, X86_EDX, nursery_shift);
4053                         x86_alu_reg_imm (code, X86_CMP, X86_EDX, nursery_start >> nursery_shift);
4054                         br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
4055                         x86_mov_reg_reg (code, X86_EDX, ptr, 4);
4056                         x86_shift_reg_imm (code, X86_SHR, X86_EDX, card_table_shift);
4057                         if (card_table_mask)
4058                                 x86_alu_reg_imm (code, X86_AND, X86_EDX, (int)card_table_mask);
4059                         x86_mov_membase_imm (code, X86_EDX, card_table, 1, 1);
4060                         x86_patch (br, code);
4061                         break;
4062                 }
4063 #endif
4064 #ifdef MONO_ARCH_SIMD_INTRINSICS
4065                 case OP_ADDPS:
4066                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4067                         break;
4068                 case OP_DIVPS:
4069                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4070                         break;
4071                 case OP_MULPS:
4072                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4073                         break;
4074                 case OP_SUBPS:
4075                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4076                         break;
4077                 case OP_MAXPS:
4078                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4079                         break;
4080                 case OP_MINPS:
4081                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4082                         break;
4083                 case OP_COMPPS:
4084                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4085                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4086                         break;
4087                 case OP_ANDPS:
4088                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4089                         break;
4090                 case OP_ANDNPS:
4091                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4092                         break;
4093                 case OP_ORPS:
4094                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4095                         break;
4096                 case OP_XORPS:
4097                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4098                         break;
4099                 case OP_SQRTPS:
4100                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4101                         break;
4102                 case OP_RSQRTPS:
4103                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
4104                         break;
4105                 case OP_RCPPS:
4106                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
4107                         break;
4108                 case OP_ADDSUBPS:
4109                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4110                         break;
4111                 case OP_HADDPS:
4112                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4113                         break;
4114                 case OP_HSUBPS:
4115                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4116                         break;
4117                 case OP_DUPPS_HIGH:
4118                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
4119                         break;
4120                 case OP_DUPPS_LOW:
4121                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
4122                         break;
4123
4124                 case OP_PSHUFLEW_HIGH:
4125                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4126                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
4127                         break;
4128                 case OP_PSHUFLEW_LOW:
4129                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4130                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
4131                         break;
4132                 case OP_PSHUFLED:
4133                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4134                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
4135                         break;
4136
4137                 case OP_ADDPD:
4138                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4139                         break;
4140                 case OP_DIVPD:
4141                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4142                         break;
4143                 case OP_MULPD:
4144                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4145                         break;
4146                 case OP_SUBPD:
4147                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4148                         break;
4149                 case OP_MAXPD:
4150                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4151                         break;
4152                 case OP_MINPD:
4153                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4154                         break;
4155                 case OP_COMPPD:
4156                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4157                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4158                         break;
4159                 case OP_ANDPD:
4160                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4161                         break;
4162                 case OP_ANDNPD:
4163                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4164                         break;
4165                 case OP_ORPD:
4166                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4167                         break;
4168                 case OP_XORPD:
4169                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4170                         break;
4171                 case OP_SQRTPD:
4172                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4173                         break;
4174                 case OP_ADDSUBPD:
4175                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4176                         break;
4177                 case OP_HADDPD:
4178                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4179                         break;
4180                 case OP_HSUBPD:
4181                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4182                         break;
4183                 case OP_DUPPD:
4184                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
4185                         break;
4186                         
4187                 case OP_EXTRACT_MASK:
4188                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
4189                         break;
4190         
4191                 case OP_PAND:
4192                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
4193                         break;
4194                 case OP_POR:
4195                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
4196                         break;
4197                 case OP_PXOR:
4198                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
4199                         break;
4200
4201                 case OP_PADDB:
4202                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
4203                         break;
4204                 case OP_PADDW:
4205                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
4206                         break;
4207                 case OP_PADDD:
4208                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
4209                         break;
4210                 case OP_PADDQ:
4211                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
4212                         break;
4213
4214                 case OP_PSUBB:
4215                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
4216                         break;
4217                 case OP_PSUBW:
4218                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
4219                         break;
4220                 case OP_PSUBD:
4221                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
4222                         break;
4223                 case OP_PSUBQ:
4224                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
4225                         break;
4226
4227                 case OP_PMAXB_UN:
4228                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
4229                         break;
4230                 case OP_PMAXW_UN:
4231                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
4232                         break;
4233                 case OP_PMAXD_UN:
4234                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
4235                         break;
4236                 
4237                 case OP_PMAXB:
4238                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
4239                         break;
4240                 case OP_PMAXW:
4241                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
4242                         break;
4243                 case OP_PMAXD:
4244                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4245                         break;
4246
4247                 case OP_PAVGB_UN:
4248                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4249                         break;
4250                 case OP_PAVGW_UN:
4251                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4252                         break;
4253
4254                 case OP_PMINB_UN:
4255                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4256                         break;
4257                 case OP_PMINW_UN:
4258                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4259                         break;
4260                 case OP_PMIND_UN:
4261                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4262                         break;
4263
4264                 case OP_PMINB:
4265                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4266                         break;
4267                 case OP_PMINW:
4268                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4269                         break;
4270                 case OP_PMIND:
4271                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4272                         break;
4273
4274                 case OP_PCMPEQB:
4275                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4276                         break;
4277                 case OP_PCMPEQW:
4278                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4279                         break;
4280                 case OP_PCMPEQD:
4281                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4282                         break;
4283                 case OP_PCMPEQQ:
4284                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4285                         break;
4286
4287                 case OP_PCMPGTB:
4288                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4289                         break;
4290                 case OP_PCMPGTW:
4291                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4292                         break;
4293                 case OP_PCMPGTD:
4294                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4295                         break;
4296                 case OP_PCMPGTQ:
4297                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4298                         break;
4299
4300                 case OP_PSUM_ABS_DIFF:
4301                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4302                         break;
4303
4304                 case OP_UNPACK_LOWB:
4305                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4306                         break;
4307                 case OP_UNPACK_LOWW:
4308                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4309                         break;
4310                 case OP_UNPACK_LOWD:
4311                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4312                         break;
4313                 case OP_UNPACK_LOWQ:
4314                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4315                         break;
4316                 case OP_UNPACK_LOWPS:
4317                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4318                         break;
4319                 case OP_UNPACK_LOWPD:
4320                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4321                         break;
4322
4323                 case OP_UNPACK_HIGHB:
4324                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4325                         break;
4326                 case OP_UNPACK_HIGHW:
4327                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4328                         break;
4329                 case OP_UNPACK_HIGHD:
4330                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4331                         break;
4332                 case OP_UNPACK_HIGHQ:
4333                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4334                         break;
4335                 case OP_UNPACK_HIGHPS:
4336                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4337                         break;
4338                 case OP_UNPACK_HIGHPD:
4339                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4340                         break;
4341
4342                 case OP_PACKW:
4343                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4344                         break;
4345                 case OP_PACKD:
4346                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4347                         break;
4348                 case OP_PACKW_UN:
4349                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4350                         break;
4351                 case OP_PACKD_UN:
4352                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4353                         break;
4354
4355                 case OP_PADDB_SAT_UN:
4356                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4357                         break;
4358                 case OP_PSUBB_SAT_UN:
4359                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4360                         break;
4361                 case OP_PADDW_SAT_UN:
4362                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4363                         break;
4364                 case OP_PSUBW_SAT_UN:
4365                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4366                         break;
4367
4368                 case OP_PADDB_SAT:
4369                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4370                         break;
4371                 case OP_PSUBB_SAT:
4372                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4373                         break;
4374                 case OP_PADDW_SAT:
4375                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4376                         break;
4377                 case OP_PSUBW_SAT:
4378                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4379                         break;
4380                         
4381                 case OP_PMULW:
4382                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4383                         break;
4384                 case OP_PMULD:
4385                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4386                         break;
4387                 case OP_PMULQ:
4388                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4389                         break;
4390                 case OP_PMULW_HIGH_UN:
4391                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4392                         break;
4393                 case OP_PMULW_HIGH:
4394                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4395                         break;
4396
4397                 case OP_PSHRW:
4398                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4399                         break;
4400                 case OP_PSHRW_REG:
4401                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4402                         break;
4403
4404                 case OP_PSARW:
4405                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4406                         break;
4407                 case OP_PSARW_REG:
4408                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4409                         break;
4410
4411                 case OP_PSHLW:
4412                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4413                         break;
4414                 case OP_PSHLW_REG:
4415                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4416                         break;
4417
4418                 case OP_PSHRD:
4419                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4420                         break;
4421                 case OP_PSHRD_REG:
4422                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4423                         break;
4424
4425                 case OP_PSARD:
4426                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4427                         break;
4428                 case OP_PSARD_REG:
4429                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4430                         break;
4431
4432                 case OP_PSHLD:
4433                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4434                         break;
4435                 case OP_PSHLD_REG:
4436                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4437                         break;
4438
4439                 case OP_PSHRQ:
4440                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4441                         break;
4442                 case OP_PSHRQ_REG:
4443                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4444                         break;
4445
4446                 case OP_PSHLQ:
4447                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4448                         break;
4449                 case OP_PSHLQ_REG:
4450                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4451                         break;          
4452                         
4453                 case OP_ICONV_TO_X:
4454                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4455                         break;
4456                 case OP_EXTRACT_I4:
4457                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4458                         break;
4459                 case OP_EXTRACT_I1:
4460                 case OP_EXTRACT_U1:
4461                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4462                         if (ins->inst_c0)
4463                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4464                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4465                         break;
4466                 case OP_EXTRACT_I2:
4467                 case OP_EXTRACT_U2:
4468                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4469                         if (ins->inst_c0)
4470                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4471                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4472                         break;
4473                 case OP_EXTRACT_R8:
4474                         if (ins->inst_c0)
4475                                 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);
4476                         else
4477                                 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);
4478                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4479                         break;
4480
4481                 case OP_INSERT_I2:
4482                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4483                         break;
4484                 case OP_EXTRACTX_U2:
4485                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4486                         break;
4487                 case OP_INSERTX_U1_SLOW:
4488                         /*sreg1 is the extracted ireg (scratch)
4489                         /sreg2 is the to be inserted ireg (scratch)
4490                         /dreg is the xreg to receive the value*/
4491
4492                         /*clear the bits from the extracted word*/
4493                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4494                         /*shift the value to insert if needed*/
4495                         if (ins->inst_c0 & 1)
4496                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4497                         /*join them together*/
4498                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4499                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4500                         break;
4501                 case OP_INSERTX_I4_SLOW:
4502                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4503                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4504                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4505                         break;
4506
4507                 case OP_INSERTX_R4_SLOW:
4508                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4509                         /*TODO if inst_c0 == 0 use movss*/
4510                         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);
4511                         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);
4512                         break;
4513                 case OP_INSERTX_R8_SLOW:
4514                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4515                         if (ins->inst_c0)
4516                                 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);
4517                         else
4518                                 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);
4519                         break;
4520
4521                 case OP_STOREX_MEMBASE_REG:
4522                 case OP_STOREX_MEMBASE:
4523                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4524                         break;
4525                 case OP_LOADX_MEMBASE:
4526                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4527                         break;
4528                 case OP_LOADX_ALIGNED_MEMBASE:
4529                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4530                         break;
4531                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4532                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4533                         break;
4534                 case OP_STOREX_NTA_MEMBASE_REG:
4535                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4536                         break;
4537                 case OP_PREFETCH_MEMBASE:
4538                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4539
4540                         break;
4541                 case OP_XMOVE:
4542                         /*FIXME the peephole pass should have killed this*/
4543                         if (ins->dreg != ins->sreg1)
4544                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4545                         break;          
4546                 case OP_XZERO:
4547                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4548                         break;
4549                 case OP_ICONV_TO_R8_RAW:
4550                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4551                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4552                         break;
4553
4554                 case OP_FCONV_TO_R8_X:
4555                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4556                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4557                         break;
4558
4559                 case OP_XCONV_R8_TO_I4:
4560                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4561                         switch (ins->backend.source_opcode) {
4562                         case OP_FCONV_TO_I1:
4563                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4564                                 break;
4565                         case OP_FCONV_TO_U1:
4566                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4567                                 break;
4568                         case OP_FCONV_TO_I2:
4569                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4570                                 break;
4571                         case OP_FCONV_TO_U2:
4572                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4573                                 break;
4574                         }                       
4575                         break;
4576
4577                 case OP_EXPAND_I1:
4578                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4579                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4580                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4581                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4582                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4583                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4584                         break;
4585                 case OP_EXPAND_I2:
4586                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4587                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4588                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4589                         break;
4590                 case OP_EXPAND_I4:
4591                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4592                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4593                         break;
4594                 case OP_EXPAND_R4:
4595                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4596                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4597                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4598                         break;
4599                 case OP_EXPAND_R8:
4600                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4601                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4602                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4603                         break;
4604 #endif
4605                 case OP_LIVERANGE_START: {
4606                         if (cfg->verbose_level > 1)
4607                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4608                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4609                         break;
4610                 }
4611                 case OP_LIVERANGE_END: {
4612                         if (cfg->verbose_level > 1)
4613                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4614                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4615                         break;
4616                 }
4617                 default:
4618                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
4619                         g_assert_not_reached ();
4620                 }
4621
4622                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
4623 #ifndef __native_client_codegen__
4624                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4625                                            mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4626                         g_assert_not_reached ();
4627 #endif  /* __native_client_codegen__ */
4628                 }
4629                
4630                 cpos += max_len;
4631         }
4632
4633         cfg->code_len = code - cfg->native_code;
4634 }
4635
4636 #endif /* DISABLE_JIT */
4637
4638 void
4639 mono_arch_register_lowlevel_calls (void)
4640 {
4641 }
4642
4643 void
4644 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4645 {
4646         MonoJumpInfo *patch_info;
4647         gboolean compile_aot = !run_cctors;
4648
4649         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4650                 unsigned char *ip = patch_info->ip.i + code;
4651                 const unsigned char *target;
4652
4653                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4654
4655                 if (compile_aot) {
4656                         switch (patch_info->type) {
4657                         case MONO_PATCH_INFO_BB:
4658                         case MONO_PATCH_INFO_LABEL:
4659                                 break;
4660                         default:
4661                                 /* No need to patch these */
4662                                 continue;
4663                         }
4664                 }
4665
4666                 switch (patch_info->type) {
4667                 case MONO_PATCH_INFO_IP:
4668                         *((gconstpointer *)(ip)) = target;
4669                         break;
4670                 case MONO_PATCH_INFO_CLASS_INIT: {
4671                         guint8 *code = ip;
4672                         /* Might already been changed to a nop */
4673                         x86_call_code (code, 0);
4674                         x86_patch (ip, target);
4675                         break;
4676                 }
4677                 case MONO_PATCH_INFO_ABS:
4678                 case MONO_PATCH_INFO_METHOD:
4679                 case MONO_PATCH_INFO_METHOD_JUMP:
4680                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4681                 case MONO_PATCH_INFO_BB:
4682                 case MONO_PATCH_INFO_LABEL:
4683                 case MONO_PATCH_INFO_RGCTX_FETCH:
4684                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
4685                 case MONO_PATCH_INFO_MONITOR_ENTER:
4686                 case MONO_PATCH_INFO_MONITOR_EXIT:
4687                         x86_patch (ip, target);
4688                         break;
4689                 case MONO_PATCH_INFO_NONE:
4690                         break;
4691                 default: {
4692                         guint32 offset = mono_arch_get_patch_offset (ip);
4693                         *((gconstpointer *)(ip + offset)) = target;
4694                         break;
4695                 }
4696                 }
4697         }
4698 }
4699
4700 guint8 *
4701 mono_arch_emit_prolog (MonoCompile *cfg)
4702 {
4703         MonoMethod *method = cfg->method;
4704         MonoBasicBlock *bb;
4705         MonoMethodSignature *sig;
4706         MonoInst *inst;
4707         int alloc_size, pos, max_offset, i, cfa_offset;
4708         guint8 *code;
4709         gboolean need_stack_frame;
4710 #ifdef __native_client_codegen__
4711         guint alignment_check;
4712 #endif
4713
4714         cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
4715
4716         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4717                 cfg->code_size += 512;
4718
4719 #ifdef __native_client_codegen__
4720         /* native_code_alloc is not 32-byte aligned, native_code is. */
4721         cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment);
4722
4723         /* Align native_code to next nearest kNaclAlignment byte. */
4724         cfg->native_code = (guint)cfg->native_code_alloc + kNaClAlignment; 
4725         cfg->native_code = (guint)cfg->native_code & ~kNaClAlignmentMask;
4726         
4727         code = cfg->native_code;
4728
4729         alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
4730         g_assert(alignment_check == 0);
4731 #else
4732         code = cfg->native_code = g_malloc (cfg->code_size);
4733 #endif
4734
4735         /* Offset between RSP and the CFA */
4736         cfa_offset = 0;
4737
4738         // CFA = sp + 4
4739         cfa_offset = sizeof (gpointer);
4740         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
4741         // IP saved at CFA - 4
4742         /* There is no IP reg on x86 */
4743         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
4744
4745         need_stack_frame = needs_stack_frame (cfg);
4746
4747         if (need_stack_frame) {
4748                 x86_push_reg (code, X86_EBP);
4749                 cfa_offset += sizeof (gpointer);
4750                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4751                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
4752                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
4753                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
4754         }
4755
4756         alloc_size = cfg->stack_offset;
4757         pos = 0;
4758
4759         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4760                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
4761                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
4762                         guint8 *buf, *no_domain_branch;
4763
4764                         code = mono_x86_emit_tls_get (code, X86_EAX, appdomain_tls_offset);
4765                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
4766                         no_domain_branch = code;
4767                         x86_branch8 (code, X86_CC_NE, 0, 0);
4768                         code = mono_x86_emit_tls_get ( code, X86_EAX, lmf_tls_offset);
4769                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
4770                         buf = code;
4771                         x86_branch8 (code, X86_CC_NE, 0, 0);
4772                         x86_patch (no_domain_branch, code);
4773                         x86_push_imm (code, cfg->domain);
4774                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4775                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4776                         x86_patch (buf, code);
4777 #ifdef TARGET_WIN32
4778                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4779                         /* FIXME: Add a separate key for LMF to avoid this */
4780                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4781 #endif
4782                 }
4783                 else {
4784                         if (cfg->compile_aot) {
4785                                 /* 
4786                                  * This goes before the saving of callee saved regs, so save the got reg
4787                                  * ourselves.
4788                                  */
4789                                 x86_push_reg (code, MONO_ARCH_GOT_REG);
4790                                 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
4791                                 x86_push_imm (code, 0);
4792                         } else {
4793                                 x86_push_imm (code, cfg->domain);
4794                         }
4795                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4796                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4797                         if (cfg->compile_aot)
4798                                 x86_pop_reg (code, MONO_ARCH_GOT_REG);
4799                 }
4800         }
4801
4802         if (method->save_lmf) {
4803                 pos += sizeof (MonoLMF);
4804
4805                 /* save the current IP */
4806                 if (cfg->compile_aot) {
4807                         /* This pushes the current ip */
4808                         x86_call_imm (code, 0);
4809                 } else {
4810                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4811                         x86_push_imm_template (code);
4812                 }
4813                 cfa_offset += sizeof (gpointer);
4814
4815                 /* save all caller saved regs */
4816                 x86_push_reg (code, X86_EBP);
4817                 cfa_offset += sizeof (gpointer);
4818                 x86_push_reg (code, X86_ESI);
4819                 cfa_offset += sizeof (gpointer);
4820                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4821                 x86_push_reg (code, X86_EDI);
4822                 cfa_offset += sizeof (gpointer);
4823                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4824                 x86_push_reg (code, X86_EBX);
4825                 cfa_offset += sizeof (gpointer);
4826                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4827
4828                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4829                         /*
4830                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4831                          * through the mono_lmf_addr TLS variable.
4832                          */
4833                         /* %eax = previous_lmf */
4834                         x86_prefix (code, X86_GS_PREFIX);
4835                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
4836                         /* skip esp + method_info + lmf */
4837                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
4838                         /* push previous_lmf */
4839                         x86_push_reg (code, X86_EAX);
4840                         /* new lmf = ESP */
4841                         x86_prefix (code, X86_GS_PREFIX);
4842                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
4843                 } else {
4844                         /* get the address of lmf for the current thread */
4845                         /* 
4846                          * This is performance critical so we try to use some tricks to make
4847                          * it fast.
4848                          */                                                                        
4849
4850                         if (lmf_addr_tls_offset != -1) {
4851                                 /* Load lmf quicky using the GS register */
4852                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
4853 #ifdef TARGET_WIN32
4854                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4855                                 /* FIXME: Add a separate key for LMF to avoid this */
4856                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4857 #endif
4858                         } else {
4859                                 if (cfg->compile_aot)
4860                                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
4861                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
4862                         }
4863
4864                         /* Skip esp + method info */
4865                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
4866
4867                         /* push lmf */
4868                         x86_push_reg (code, X86_EAX); 
4869                         /* push *lfm (previous_lmf) */
4870                         x86_push_membase (code, X86_EAX, 0);
4871                         /* *(lmf) = ESP */
4872                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
4873                 }
4874         } else {
4875
4876                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4877                         x86_push_reg (code, X86_EBX);
4878                         pos += 4;
4879                         cfa_offset += sizeof (gpointer);
4880                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4881                 }
4882
4883                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4884                         x86_push_reg (code, X86_EDI);
4885                         pos += 4;
4886                         cfa_offset += sizeof (gpointer);
4887                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4888                 }
4889
4890                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4891                         x86_push_reg (code, X86_ESI);
4892                         pos += 4;
4893                         cfa_offset += sizeof (gpointer);
4894                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4895                 }
4896         }
4897
4898         alloc_size -= pos;
4899
4900         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
4901         if (mono_do_x86_stack_align && need_stack_frame) {
4902                 int tot = alloc_size + pos + 4; /* ret ip */
4903                 if (need_stack_frame)
4904                         tot += 4; /* ebp */
4905                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
4906                 if (tot)
4907                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
4908         }
4909
4910         if (alloc_size) {
4911                 /* See mono_emit_stack_alloc */
4912 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4913                 guint32 remaining_size = alloc_size;
4914                 /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
4915                 guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 8; /*8 is the max size of x86_alu_reg_imm + x86_test_membase_reg*/
4916                 guint32 offset = code - cfg->native_code;
4917                 if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
4918                         while (required_code_size >= (cfg->code_size - offset))
4919                                 cfg->code_size *= 2;
4920                         cfg->native_code = mono_realloc_native_code(cfg);
4921                         code = cfg->native_code + offset;
4922                         mono_jit_stats.code_reallocs++;
4923                 }
4924                 while (remaining_size >= 0x1000) {
4925                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
4926                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
4927                         remaining_size -= 0x1000;
4928                 }
4929                 if (remaining_size)
4930                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
4931 #else
4932                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4933 #endif
4934
4935                 g_assert (need_stack_frame);
4936         }
4937
4938         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
4939                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
4940                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
4941         }
4942
4943 #if DEBUG_STACK_ALIGNMENT
4944         /* check the stack is aligned */
4945         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
4946                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
4947                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
4948                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4949                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4950                 x86_breakpoint (code);
4951         }
4952 #endif
4953
4954         /* compute max_offset in order to use short forward jumps */
4955         max_offset = 0;
4956         if (cfg->opt & MONO_OPT_BRANCH) {
4957                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4958                         MonoInst *ins;
4959                         bb->max_offset = max_offset;
4960
4961                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4962                                 max_offset += 6;
4963                         /* max alignment for loops */
4964                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4965                                 max_offset += LOOP_ALIGNMENT;
4966 #ifdef __native_client_codegen__
4967                         /* max alignment for native client */
4968                         max_offset += kNaClAlignment;
4969 #endif
4970                         MONO_BB_FOR_EACH_INS (bb, ins) {
4971                                 if (ins->opcode == OP_LABEL)
4972                                         ins->inst_c1 = max_offset;
4973 #ifdef __native_client_codegen__
4974                                 {
4975                                         int space_in_block = kNaClAlignment -
4976                                                 ((max_offset + cfg->code_len) & kNaClAlignmentMask);
4977                                         int max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4978                                         if (space_in_block < max_len && max_len < kNaClAlignment) {
4979                                                 max_offset += space_in_block;
4980                                         }
4981                                 }
4982 #endif  /* __native_client_codegen__ */
4983                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4984                         }
4985                 }
4986         }
4987
4988         /* store runtime generic context */
4989         if (cfg->rgctx_var) {
4990                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4991
4992                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4993         }
4994
4995         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4996                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4997
4998         /* load arguments allocated to register from the stack */
4999         sig = mono_method_signature (method);
5000         pos = 0;
5001
5002         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5003                 inst = cfg->args [pos];
5004                 if (inst->opcode == OP_REGVAR) {
5005                         g_assert (need_stack_frame);
5006                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
5007                         if (cfg->verbose_level > 2)
5008                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5009                 }
5010                 pos++;
5011         }
5012
5013         cfg->code_len = code - cfg->native_code;
5014
5015         g_assert (cfg->code_len < cfg->code_size);
5016
5017         return code;
5018 }
5019
5020 void
5021 mono_arch_emit_epilog (MonoCompile *cfg)
5022 {
5023         MonoMethod *method = cfg->method;
5024         MonoMethodSignature *sig = mono_method_signature (method);
5025         int quad, pos;
5026         guint32 stack_to_pop;
5027         guint8 *code;
5028         int max_epilog_size = 16;
5029         CallInfo *cinfo;
5030         gboolean need_stack_frame = needs_stack_frame (cfg);
5031
5032         if (cfg->method->save_lmf)
5033                 max_epilog_size += 128;
5034
5035         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5036                 cfg->code_size *= 2;
5037                 cfg->native_code = mono_realloc_native_code(cfg);
5038                 mono_jit_stats.code_reallocs++;
5039         }
5040
5041         code = cfg->native_code + cfg->code_len;
5042
5043         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5044                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5045
5046         /* the code restoring the registers must be kept in sync with OP_JMP */
5047         pos = 0;
5048         
5049         if (method->save_lmf) {
5050                 gint32 prev_lmf_reg;
5051                 gint32 lmf_offset = -sizeof (MonoLMF);
5052
5053                 /* check if we need to restore protection of the stack after a stack overflow */
5054                 if (mono_get_jit_tls_offset () != -1) {
5055                         guint8 *patch;
5056                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
5057                         /* we load the value in a separate instruction: this mechanism may be
5058                          * used later as a safer way to do thread interruption
5059                          */
5060                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
5061                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5062                         patch = code;
5063                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
5064                         /* note that the call trampoline will preserve eax/edx */
5065                         x86_call_reg (code, X86_ECX);
5066                         x86_patch (patch, code);
5067                 } else {
5068                         /* FIXME: maybe save the jit tls in the prolog */
5069                 }
5070                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5071                         /*
5072                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5073                          * through the mono_lmf_addr TLS variable.
5074                          */
5075                         /* reg = previous_lmf */
5076                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5077
5078                         /* lmf = previous_lmf */
5079                         x86_prefix (code, X86_GS_PREFIX);
5080                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
5081                 } else {
5082                         /* Find a spare register */
5083                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
5084                         case MONO_TYPE_I8:
5085                         case MONO_TYPE_U8:
5086                                 prev_lmf_reg = X86_EDI;
5087                                 cfg->used_int_regs |= (1 << X86_EDI);
5088                                 break;
5089                         default:
5090                                 prev_lmf_reg = X86_EDX;
5091                                 break;
5092                         }
5093
5094                         /* reg = previous_lmf */
5095                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5096
5097                         /* ecx = lmf */
5098                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
5099
5100                         /* *(lmf) = previous_lmf */
5101                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
5102                 }
5103
5104                 /* restore caller saved regs */
5105                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5106                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
5107                 }
5108
5109                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5110                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
5111                 }
5112                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5113                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
5114                 }
5115
5116                 /* EBP is restored by LEAVE */
5117         } else {
5118                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5119                         pos -= 4;
5120                 }
5121                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5122                         pos -= 4;
5123                 }
5124                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5125                         pos -= 4;
5126                 }
5127
5128                 if (pos) {
5129                         g_assert (need_stack_frame);
5130                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
5131                 }
5132
5133                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5134                         x86_pop_reg (code, X86_ESI);
5135                 }
5136                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5137                         x86_pop_reg (code, X86_EDI);
5138                 }
5139                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5140                         x86_pop_reg (code, X86_EBX);
5141                 }
5142         }
5143
5144         /* Load returned vtypes into registers if needed */
5145         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
5146         if (cinfo->ret.storage == ArgValuetypeInReg) {
5147                 for (quad = 0; quad < 2; quad ++) {
5148                         switch (cinfo->ret.pair_storage [quad]) {
5149                         case ArgInIReg:
5150                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
5151                                 break;
5152                         case ArgOnFloatFpStack:
5153                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
5154                                 break;
5155                         case ArgOnDoubleFpStack:
5156                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
5157                                 break;
5158                         case ArgNone:
5159                                 break;
5160                         default:
5161                                 g_assert_not_reached ();
5162                         }
5163                 }
5164         }
5165
5166         if (need_stack_frame)
5167                 x86_leave (code);
5168
5169         if (CALLCONV_IS_STDCALL (sig)) {
5170                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
5171
5172                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
5173         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
5174                 stack_to_pop = 4;
5175         else
5176                 stack_to_pop = 0;
5177
5178         if (stack_to_pop) {
5179                 g_assert (need_stack_frame);
5180                 x86_ret_imm (code, stack_to_pop);
5181         } else {
5182                 x86_ret (code);
5183         }
5184
5185         cfg->code_len = code - cfg->native_code;
5186
5187         g_assert (cfg->code_len < cfg->code_size);
5188 }
5189
5190 void
5191 mono_arch_emit_exceptions (MonoCompile *cfg)
5192 {
5193         MonoJumpInfo *patch_info;
5194         int nthrows, i;
5195         guint8 *code;
5196         MonoClass *exc_classes [16];
5197         guint8 *exc_throw_start [16], *exc_throw_end [16];
5198         guint32 code_size;
5199         int exc_count = 0;
5200
5201         /* Compute needed space */
5202         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5203                 if (patch_info->type == MONO_PATCH_INFO_EXC)
5204                         exc_count++;
5205         }
5206
5207         /* 
5208          * make sure we have enough space for exceptions
5209          * 16 is the size of two push_imm instructions and a call
5210          */
5211         if (cfg->compile_aot)
5212                 code_size = exc_count * 32;
5213         else
5214                 code_size = exc_count * 16;
5215
5216         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
5217                 cfg->code_size *= 2;
5218                 cfg->native_code = mono_realloc_native_code(cfg);
5219                 mono_jit_stats.code_reallocs++;
5220         }
5221
5222         code = cfg->native_code + cfg->code_len;
5223
5224         nthrows = 0;
5225         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5226                 switch (patch_info->type) {
5227                 case MONO_PATCH_INFO_EXC: {
5228                         MonoClass *exc_class;
5229                         guint8 *buf, *buf2;
5230                         guint32 throw_ip;
5231
5232                         x86_patch (patch_info->ip.i + cfg->native_code, code);
5233
5234                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5235                         g_assert (exc_class);
5236                         throw_ip = patch_info->ip.i;
5237
5238                         /* Find a throw sequence for the same exception class */
5239                         for (i = 0; i < nthrows; ++i)
5240                                 if (exc_classes [i] == exc_class)
5241                                         break;
5242                         if (i < nthrows) {
5243                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
5244                                 x86_jump_code (code, exc_throw_start [i]);
5245                                 patch_info->type = MONO_PATCH_INFO_NONE;
5246                         }
5247                         else {
5248                                 guint32 size;
5249
5250                                 /* Compute size of code following the push <OFFSET> */
5251 #ifdef __native_client_codegen__
5252                                 code = mono_nacl_align (code);
5253                                 size = kNaClAlignment;
5254 #else
5255                                 size = 5 + 5;
5256 #endif
5257                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
5258
5259                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
5260                                         /* Use the shorter form */
5261                                         buf = buf2 = code;
5262                                         x86_push_imm (code, 0);
5263                                 }
5264                                 else {
5265                                         buf = code;
5266                                         x86_push_imm (code, 0xf0f0f0f0);
5267                                         buf2 = code;
5268                                 }
5269
5270                                 if (nthrows < 16) {
5271                                         exc_classes [nthrows] = exc_class;
5272                                         exc_throw_start [nthrows] = code;
5273                                 }
5274
5275                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
5276                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
5277                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5278                                 patch_info->ip.i = code - cfg->native_code;
5279                                 x86_call_code (code, 0);
5280                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
5281                                 while (buf < buf2)
5282                                         x86_nop (buf);
5283
5284                                 if (nthrows < 16) {
5285                                         exc_throw_end [nthrows] = code;
5286                                         nthrows ++;
5287                                 }
5288                         }
5289                         break;
5290                 }
5291                 default:
5292                         /* do nothing */
5293                         break;
5294                 }
5295         }
5296
5297         cfg->code_len = code - cfg->native_code;
5298
5299         g_assert (cfg->code_len < cfg->code_size);
5300 }
5301
5302 void
5303 mono_arch_flush_icache (guint8 *code, gint size)
5304 {
5305         /* not needed */
5306 }
5307
5308 void
5309 mono_arch_flush_register_windows (void)
5310 {
5311 }
5312
5313 gboolean 
5314 mono_arch_is_inst_imm (gint64 imm)
5315 {
5316         return TRUE;
5317 }
5318
5319 /*
5320  * Support for fast access to the thread-local lmf structure using the GS
5321  * segment register on NPTL + kernel 2.6.x.
5322  */
5323
5324 static gboolean tls_offset_inited = FALSE;
5325
5326 void
5327 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5328 {
5329         if (!tls_offset_inited) {
5330                 if (!getenv ("MONO_NO_TLS")) {
5331 #ifdef TARGET_WIN32
5332                         /* 
5333                          * We need to init this multiple times, since when we are first called, the key might not
5334                          * be initialized yet.
5335                          */
5336                         appdomain_tls_offset = mono_domain_get_tls_key ();
5337                         lmf_tls_offset = mono_get_jit_tls_key ();
5338
5339                         /* Only 64 tls entries can be accessed using inline code */
5340                         if (appdomain_tls_offset >= 64)
5341                                 appdomain_tls_offset = -1;
5342                         if (lmf_tls_offset >= 64)
5343                                 lmf_tls_offset = -1;
5344 #else
5345 #if MONO_XEN_OPT
5346                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5347 #endif
5348                         tls_offset_inited = TRUE;
5349                         appdomain_tls_offset = mono_domain_get_tls_offset ();
5350                         lmf_tls_offset = mono_get_lmf_tls_offset ();
5351                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5352 #endif
5353                 }
5354         }               
5355 }
5356
5357 void
5358 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5359 {
5360 }
5361
5362 #ifdef MONO_ARCH_HAVE_IMT
5363
5364 // Linear handler, the bsearch head compare is shorter
5365 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5366 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5367 //        x86_patch(ins,target)
5368 //[1 + 5] x86_jump_mem(inst,mem)
5369
5370 #define CMP_SIZE 6
5371 #ifdef __native_client_codegen__
5372 /* These constants should be coming from cpu-x86.md            */
5373 /* I suspect the size calculation below is actually incorrect. */
5374 /* TODO: fix the calculation that uses these sizes.            */
5375 #define BR_SMALL_SIZE 16
5376 #define BR_LARGE_SIZE 12
5377 #else
5378 #define BR_SMALL_SIZE 2
5379 #define BR_LARGE_SIZE 5
5380 #endif  /* __native_client_codegen__ */
5381 #define JUMP_IMM_SIZE 6
5382 #define ENABLE_WRONG_METHOD_CHECK 0
5383 #define DEBUG_IMT 0
5384
5385 static int
5386 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5387 {
5388         int i, distance = 0;
5389         for (i = start; i < target; ++i)
5390                 distance += imt_entries [i]->chunk_size;
5391         return distance;
5392 }
5393
5394 /*
5395  * LOCKING: called with the domain lock held
5396  */
5397 gpointer
5398 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5399         gpointer fail_tramp)
5400 {
5401         int i;
5402         int size = 0;
5403         guint8 *code, *start;
5404
5405 #ifdef __native_client_codegen__
5406         /* g_print("mono_arch_build_imt_thunk needs to be aligned.\n"); */
5407 #endif
5408         for (i = 0; i < count; ++i) {
5409                 MonoIMTCheckItem *item = imt_entries [i];
5410                 if (item->is_equals) {
5411                         if (item->check_target_idx) {
5412                                 if (!item->compare_done)
5413                                         item->chunk_size += CMP_SIZE;
5414                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5415                         } else {
5416                                 if (fail_tramp) {
5417                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5418                                 } else {
5419                                         item->chunk_size += JUMP_IMM_SIZE;
5420 #if ENABLE_WRONG_METHOD_CHECK
5421                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5422 #endif
5423                                 }
5424                         }
5425                 } else {
5426                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5427                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5428                 }
5429                 size += item->chunk_size;
5430         }
5431         if (fail_tramp)
5432                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5433         else
5434                 code = mono_domain_code_reserve (domain, size);
5435         start = code;
5436         for (i = 0; i < count; ++i) {
5437                 MonoIMTCheckItem *item = imt_entries [i];
5438                 item->code_target = code;
5439                 if (item->is_equals) {
5440                         if (item->check_target_idx) {
5441                                 if (!item->compare_done)
5442                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5443                                 item->jmp_code = code;
5444                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5445                                 if (item->has_target_code)
5446                                         x86_jump_code (code, item->value.target_code);
5447                                 else
5448                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5449                         } else {
5450                                 if (fail_tramp) {
5451                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5452                                         item->jmp_code = code;
5453                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5454                                         if (item->has_target_code)
5455                                                 x86_jump_code (code, item->value.target_code);
5456                                         else
5457                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5458                                         x86_patch (item->jmp_code, code);
5459                                         x86_jump_code (code, fail_tramp);
5460                                         item->jmp_code = NULL;
5461                                 } else {
5462                                         /* enable the commented code to assert on wrong method */
5463 #if ENABLE_WRONG_METHOD_CHECK
5464                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5465                                         item->jmp_code = code;
5466                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5467 #endif
5468                                         if (item->has_target_code)
5469                                                 x86_jump_code (code, item->value.target_code);
5470                                         else
5471                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5472 #if ENABLE_WRONG_METHOD_CHECK
5473                                         x86_patch (item->jmp_code, code);
5474                                         x86_breakpoint (code);
5475                                         item->jmp_code = NULL;
5476 #endif
5477                                 }
5478                         }
5479                 } else {
5480                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5481                         item->jmp_code = code;
5482                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5483                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5484                         else
5485                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5486                 }
5487         }
5488         /* patch the branches to get to the target items */
5489         for (i = 0; i < count; ++i) {
5490                 MonoIMTCheckItem *item = imt_entries [i];
5491                 if (item->jmp_code) {
5492                         if (item->check_target_idx) {
5493                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5494                         }
5495                 }
5496         }
5497
5498         if (!fail_tramp)
5499                 mono_stats.imt_thunks_size += code - start;
5500         g_assert (code - start <= size);
5501
5502 #if DEBUG_IMT
5503         {
5504                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5505                 mono_disassemble_code (NULL, (guint8*)start, code - start, buff);
5506                 g_free (buff);
5507         }
5508 #endif
5509         if (mono_jit_map_is_enabled ()) {
5510                 char *buff;
5511                 if (vtable)
5512                         buff = g_strdup_printf ("imt_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5513                 else
5514                         buff = g_strdup_printf ("imt_thunk_entries_%d", count);
5515                 mono_emit_jit_tramp (start, code - start, buff);
5516                 g_free (buff);
5517         }
5518
5519         return start;
5520 }
5521
5522 MonoMethod*
5523 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5524 {
5525         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5526 }
5527 #endif
5528
5529 MonoVTable*
5530 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5531 {
5532         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5533 }
5534
5535 GSList*
5536 mono_arch_get_cie_program (void)
5537 {
5538         GSList *l = NULL;
5539
5540         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
5541         mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
5542
5543         return l;
5544 }
5545
5546 MonoInst*
5547 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5548 {
5549         MonoInst *ins = NULL;
5550         int opcode = 0;
5551
5552         if (cmethod->klass == mono_defaults.math_class) {
5553                 if (strcmp (cmethod->name, "Sin") == 0) {
5554                         opcode = OP_SIN;
5555                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5556                         opcode = OP_COS;
5557                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5558                         opcode = OP_TAN;
5559                 } else if (strcmp (cmethod->name, "Atan") == 0) {
5560                         opcode = OP_ATAN;
5561                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5562                         opcode = OP_SQRT;
5563                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5564                         opcode = OP_ABS;
5565                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
5566                         opcode = OP_ROUND;
5567                 }
5568                 
5569                 if (opcode) {
5570                         MONO_INST_NEW (cfg, ins, opcode);
5571                         ins->type = STACK_R8;
5572                         ins->dreg = mono_alloc_freg (cfg);
5573                         ins->sreg1 = args [0]->dreg;
5574                         MONO_ADD_INS (cfg->cbb, ins);
5575                 }
5576
5577                 if (cfg->opt & MONO_OPT_CMOV) {
5578                         int opcode = 0;
5579
5580                         if (strcmp (cmethod->name, "Min") == 0) {
5581                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5582                                         opcode = OP_IMIN;
5583                         } else if (strcmp (cmethod->name, "Max") == 0) {
5584                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5585                                         opcode = OP_IMAX;
5586                         }               
5587
5588                         if (opcode) {
5589                                 MONO_INST_NEW (cfg, ins, opcode);
5590                                 ins->type = STACK_I4;
5591                                 ins->dreg = mono_alloc_ireg (cfg);
5592                                 ins->sreg1 = args [0]->dreg;
5593                                 ins->sreg2 = args [1]->dreg;
5594                                 MONO_ADD_INS (cfg->cbb, ins);
5595                         }
5596                 }
5597
5598 #if 0
5599                 /* OP_FREM is not IEEE compatible */
5600                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
5601                         MONO_INST_NEW (cfg, ins, OP_FREM);
5602                         ins->inst_i0 = args [0];
5603                         ins->inst_i1 = args [1];
5604                 }
5605 #endif
5606         }
5607
5608         return ins;
5609 }
5610
5611 gboolean
5612 mono_arch_print_tree (MonoInst *tree, int arity)
5613 {
5614         return 0;
5615 }
5616
5617 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5618 {
5619         MonoInst* ins;
5620
5621         return NULL;
5622
5623         if (appdomain_tls_offset == -1)
5624                 return NULL;
5625
5626         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5627         ins->inst_offset = appdomain_tls_offset;
5628         return ins;
5629 }
5630
5631 guint32
5632 mono_arch_get_patch_offset (guint8 *code)
5633 {
5634         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
5635                 return 2;
5636         else if ((code [0] == 0xba))
5637                 return 1;
5638         else if ((code [0] == 0x68))
5639                 /* push IMM */
5640                 return 1;
5641         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
5642                 /* push <OFFSET>(<REG>) */
5643                 return 2;
5644         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
5645                 /* call *<OFFSET>(<REG>) */
5646                 return 2;
5647         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
5648                 /* fldl <ADDR> */
5649                 return 2;
5650         else if ((code [0] == 0x58) && (code [1] == 0x05))
5651                 /* pop %eax; add <OFFSET>, %eax */
5652                 return 2;
5653         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
5654                 /* pop <REG>; add <OFFSET>, <REG> */
5655                 return 3;
5656         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
5657                 /* mov <REG>, imm */
5658                 return 1;
5659         else {
5660                 g_assert_not_reached ();
5661                 return -1;
5662         }
5663 }
5664
5665 /**
5666  * mono_breakpoint_clean_code:
5667  *
5668  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
5669  * breakpoints in the original code, they are removed in the copy.
5670  *
5671  * Returns TRUE if no sw breakpoint was present.
5672  */
5673 gboolean
5674 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
5675 {
5676         int i;
5677         gboolean can_write = TRUE;
5678         /*
5679          * If method_start is non-NULL we need to perform bound checks, since we access memory
5680          * at code - offset we could go before the start of the method and end up in a different
5681          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
5682          * instead.
5683          */
5684         if (!method_start || code - offset >= method_start) {
5685                 memcpy (buf, code - offset, size);
5686         } else {
5687                 int diff = code - method_start;
5688                 memset (buf, 0, size);
5689                 memcpy (buf + offset - diff, method_start, diff + size - offset);
5690         }
5691         code -= offset;
5692         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
5693                 int idx = mono_breakpoint_info_index [i];
5694                 guint8 *ptr;
5695                 if (idx < 1)
5696                         continue;
5697                 ptr = mono_breakpoint_info [idx].address;
5698                 if (ptr >= code && ptr < code + size) {
5699                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
5700                         can_write = FALSE;
5701                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
5702                         buf [ptr - code] = saved_byte;
5703                 }
5704         }
5705         return can_write;
5706 }
5707
5708 /*
5709  * mono_x86_get_this_arg_offset:
5710  *
5711  *   Return the offset of the stack location where this is passed during a virtual
5712  * call.
5713  */
5714 guint32
5715 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
5716 {
5717         return 0;
5718 }
5719
5720 gpointer
5721 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
5722 {
5723         guint32 esp = regs [X86_ESP];
5724         CallInfo *cinfo = NULL;
5725         gpointer res;
5726         int offset;
5727
5728         offset = 0;
5729
5730         /*
5731          * The stack looks like:
5732          * <other args>
5733          * <this=delegate>
5734          * <return addr>
5735          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
5736          */
5737         res = (((MonoObject**)esp) [5 + (offset / 4)]);
5738         if (cinfo)
5739                 g_free (cinfo);
5740         return res;
5741 }
5742
5743 #define MAX_ARCH_DELEGATE_PARAMS 10
5744
5745 static gpointer
5746 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
5747 {
5748         guint8 *code, *start;
5749
5750         /*
5751          * The stack contains:
5752          * <delegate>
5753          * <return addr>
5754          */
5755
5756         if (has_target) {
5757                 start = code = mono_global_codeman_reserve (64);
5758
5759                 /* Replace the this argument with the target */
5760                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
5761                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
5762                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
5763                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5764
5765                 g_assert ((code - start) < 64);
5766         } else {
5767                 int i = 0;
5768                 /* 8 for mov_reg and jump, plus 8 for each parameter */
5769 #ifdef __native_client_codegen__
5770                 /* TODO: calculate this size correctly */
5771                 int code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment;
5772 #else
5773                 int code_reserve = 8 + (param_count * 8);
5774 #endif  /* __native_client_codegen__ */
5775                 /*
5776                  * The stack contains:
5777                  * <args in reverse order>
5778                  * <delegate>
5779                  * <return addr>
5780                  *
5781                  * and we need:
5782                  * <args in reverse order>
5783                  * <return addr>
5784                  * 
5785                  * without unbalancing the stack.
5786                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
5787                  * and leaving original spot of first arg as placeholder in stack so
5788                  * when callee pops stack everything works.
5789                  */
5790
5791                 start = code = mono_global_codeman_reserve (code_reserve);
5792
5793                 /* store delegate for access to method_ptr */
5794                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
5795
5796                 /* move args up */
5797                 for (i = 0; i < param_count; ++i) {
5798                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
5799                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
5800                 }
5801
5802                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5803
5804                 g_assert ((code - start) < code_reserve);
5805         }
5806
5807         mono_debug_add_delegate_trampoline (start, code - start);
5808
5809         if (code_len)
5810                 *code_len = code - start;
5811
5812         if (mono_jit_map_is_enabled ()) {
5813                 char *buff;
5814                 if (has_target)
5815                         buff = (char*)"delegate_invoke_has_target";
5816                 else
5817                         buff = g_strdup_printf ("delegate_invoke_no_target_%d", param_count);
5818                 mono_emit_jit_tramp (start, code - start, buff);
5819                 if (!has_target)
5820                         g_free (buff);
5821         }
5822
5823         return start;
5824 }
5825
5826 GSList*
5827 mono_arch_get_delegate_invoke_impls (void)
5828 {
5829         GSList *res = NULL;
5830         guint8 *code;
5831         guint32 code_len;
5832         int i;
5833
5834         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
5835         res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
5836
5837         for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
5838                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
5839                 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
5840         }
5841
5842         return res;
5843 }
5844
5845 gpointer
5846 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5847 {
5848         guint8 *code, *start;
5849
5850         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
5851                 return NULL;
5852
5853         /* FIXME: Support more cases */
5854         if (MONO_TYPE_ISSTRUCT (sig->ret))
5855                 return NULL;
5856
5857         /*
5858          * The stack contains:
5859          * <delegate>
5860          * <return addr>
5861          */
5862
5863         if (has_target) {
5864                 static guint8* cached = NULL;
5865                 if (cached)
5866                         return cached;
5867
5868                 if (mono_aot_only)
5869                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
5870                 else
5871                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
5872
5873                 mono_memory_barrier ();
5874
5875                 cached = start;
5876         } else {
5877                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
5878                 int i = 0;
5879
5880                 for (i = 0; i < sig->param_count; ++i)
5881                         if (!mono_is_regsize_var (sig->params [i]))
5882                                 return NULL;
5883
5884                 code = cache [sig->param_count];
5885                 if (code)
5886                         return code;
5887
5888                 if (mono_aot_only) {
5889                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
5890                         start = mono_aot_get_trampoline (name);
5891                         g_free (name);
5892                 } else {
5893                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
5894                 }
5895
5896                 mono_memory_barrier ();
5897
5898                 cache [sig->param_count] = start;
5899         }
5900
5901         return start;
5902 }
5903
5904 gpointer
5905 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5906 {
5907         switch (reg) {
5908         case X86_EAX: return (gpointer)ctx->eax;
5909         case X86_EBX: return (gpointer)ctx->ebx;
5910         case X86_ECX: return (gpointer)ctx->ecx;
5911         case X86_EDX: return (gpointer)ctx->edx;
5912         case X86_ESP: return (gpointer)ctx->esp;
5913         case X86_EBP: return (gpointer)ctx->ebp;
5914         case X86_ESI: return (gpointer)ctx->esi;
5915         case X86_EDI: return (gpointer)ctx->edi;
5916         default: g_assert_not_reached ();
5917         }
5918 }
5919
5920 #ifdef MONO_ARCH_SIMD_INTRINSICS
5921
5922 static MonoInst*
5923 get_float_to_x_spill_area (MonoCompile *cfg)
5924 {
5925         if (!cfg->fconv_to_r8_x_var) {
5926                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5927                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
5928         }       
5929         return cfg->fconv_to_r8_x_var;
5930 }
5931
5932 /*
5933  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
5934  */
5935 void
5936 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5937 {
5938         MonoInst *fconv;
5939         int dreg, src_opcode;
5940
5941         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
5942                 return;
5943
5944         switch (src_opcode = ins->opcode) {
5945         case OP_FCONV_TO_I1:
5946         case OP_FCONV_TO_U1:
5947         case OP_FCONV_TO_I2:
5948         case OP_FCONV_TO_U2:
5949         case OP_FCONV_TO_I4:
5950         case OP_FCONV_TO_I:
5951                 break;
5952         default:
5953                 return;
5954         }
5955
5956         /* dreg is the IREG and sreg1 is the FREG */
5957         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
5958         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
5959         fconv->sreg1 = ins->sreg1;
5960         fconv->dreg = mono_alloc_ireg (cfg);
5961         fconv->type = STACK_VTYPE;
5962         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
5963
5964         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
5965
5966         dreg = ins->dreg;
5967         NULLIFY_INS (ins);
5968         ins->opcode = OP_XCONV_R8_TO_I4;
5969
5970         ins->klass = mono_defaults.int32_class;
5971         ins->sreg1 = fconv->dreg;
5972         ins->dreg = dreg;
5973         ins->type = STACK_I4;
5974         ins->backend.source_opcode = src_opcode;
5975 }
5976
5977 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
5978
5979 void
5980 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
5981 {
5982         MonoInst *ins;
5983         int vreg;
5984
5985         if (long_ins->opcode == OP_LNEG) {
5986                 ins = long_ins;
5987                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
5988                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
5989                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
5990                 NULLIFY_INS (ins);
5991                 return;
5992         }
5993
5994 #ifdef MONO_ARCH_SIMD_INTRINSICS
5995
5996         if (!(cfg->opt & MONO_OPT_SIMD))
5997                 return;
5998         
5999         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
6000         switch (long_ins->opcode) {
6001         case OP_EXTRACT_I8:
6002                 vreg = long_ins->sreg1;
6003         
6004                 if (long_ins->inst_c0) {
6005                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6006                         ins->klass = long_ins->klass;
6007                         ins->sreg1 = long_ins->sreg1;
6008                         ins->inst_c0 = 2;
6009                         ins->type = STACK_VTYPE;
6010                         ins->dreg = vreg = alloc_ireg (cfg);
6011                         MONO_ADD_INS (cfg->cbb, ins);
6012                 }
6013         
6014                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6015                 ins->klass = mono_defaults.int32_class;
6016                 ins->sreg1 = vreg;
6017                 ins->type = STACK_I4;
6018                 ins->dreg = long_ins->dreg + 1;
6019                 MONO_ADD_INS (cfg->cbb, ins);
6020         
6021                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6022                 ins->klass = long_ins->klass;
6023                 ins->sreg1 = long_ins->sreg1;
6024                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
6025                 ins->type = STACK_VTYPE;
6026                 ins->dreg = vreg = alloc_ireg (cfg);
6027                 MONO_ADD_INS (cfg->cbb, ins);
6028         
6029                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6030                 ins->klass = mono_defaults.int32_class;
6031                 ins->sreg1 = vreg;
6032                 ins->type = STACK_I4;
6033                 ins->dreg = long_ins->dreg + 2;
6034                 MONO_ADD_INS (cfg->cbb, ins);
6035         
6036                 long_ins->opcode = OP_NOP;
6037                 break;
6038         case OP_INSERTX_I8_SLOW:
6039                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6040                 ins->dreg = long_ins->dreg;
6041                 ins->sreg1 = long_ins->dreg;
6042                 ins->sreg2 = long_ins->sreg2 + 1;
6043                 ins->inst_c0 = long_ins->inst_c0 * 2;
6044                 MONO_ADD_INS (cfg->cbb, ins);
6045
6046                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6047                 ins->dreg = long_ins->dreg;
6048                 ins->sreg1 = long_ins->dreg;
6049                 ins->sreg2 = long_ins->sreg2 + 2;
6050                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
6051                 MONO_ADD_INS (cfg->cbb, ins);
6052
6053                 long_ins->opcode = OP_NOP;
6054                 break;
6055         case OP_EXPAND_I8:
6056                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
6057                 ins->dreg = long_ins->dreg;
6058                 ins->sreg1 = long_ins->sreg1 + 1;
6059                 ins->klass = long_ins->klass;
6060                 ins->type = STACK_VTYPE;
6061                 MONO_ADD_INS (cfg->cbb, ins);
6062
6063                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6064                 ins->dreg = long_ins->dreg;
6065                 ins->sreg1 = long_ins->dreg;
6066                 ins->sreg2 = long_ins->sreg1 + 2;
6067                 ins->inst_c0 = 1;
6068                 ins->klass = long_ins->klass;
6069                 ins->type = STACK_VTYPE;
6070                 MONO_ADD_INS (cfg->cbb, ins);
6071
6072                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6073                 ins->dreg = long_ins->dreg;
6074                 ins->sreg1 = long_ins->dreg;;
6075                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
6076                 ins->klass = long_ins->klass;
6077                 ins->type = STACK_VTYPE;
6078                 MONO_ADD_INS (cfg->cbb, ins);
6079
6080                 long_ins->opcode = OP_NOP;
6081                 break;
6082         }
6083 #endif /* MONO_ARCH_SIMD_INTRINSICS */
6084 }
6085
6086 /*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
6087 gpointer
6088 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
6089 {
6090         int offset;
6091         gpointer *sp, old_value;
6092         char *bp;
6093         const unsigned char *handler;
6094
6095         /*Decode the first instruction to figure out where did we store the spvar*/
6096         /*Our jit MUST generate the following:
6097          mov %esp, -?(%ebp)
6098          Which is encoded as: 0x89 mod_rm.
6099          mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
6100                 mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
6101                 mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
6102         */
6103         handler = clause->handler_start;
6104
6105         if (*handler != 0x89)
6106                 return NULL;
6107
6108         ++handler;
6109
6110         if (*handler == 0x65)
6111                 offset = *(signed char*)(handler + 1);
6112         else if (*handler == 0xA5)
6113                 offset = *(int*)(handler + 1);
6114         else
6115                 return NULL;
6116
6117         /*Load the spvar*/
6118         bp = MONO_CONTEXT_GET_BP (ctx);
6119         sp = *(gpointer*)(bp + offset);
6120
6121         old_value = *sp;
6122         if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
6123                 return old_value;
6124
6125         *sp = new_value;
6126
6127         return old_value;
6128 }
6129
6130 /*
6131  * mono_aot_emit_load_got_addr:
6132  *
6133  *   Emit code to load the got address.
6134  * On x86, the result is placed into EBX.
6135  */
6136 guint8*
6137 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6138 {
6139         x86_call_imm (code, 0);
6140         /* 
6141          * The patch needs to point to the pop, since the GOT offset needs 
6142          * to be added to that address.
6143          */
6144         if (cfg)
6145                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6146         else
6147                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6148         x86_pop_reg (code, MONO_ARCH_GOT_REG);
6149         x86_alu_reg_imm (code, X86_ADD, MONO_ARCH_GOT_REG, 0xf0f0f0f0);
6150
6151         return code;
6152 }
6153
6154 /*
6155  * mono_ppc_emit_load_aotconst:
6156  *
6157  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6158  * TARGET from the mscorlib GOT in full-aot code.
6159  * On x86, the GOT address is assumed to be in EBX, and the result is placed into 
6160  * EAX.
6161  */
6162 guint8*
6163 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6164 {
6165         /* Load the mscorlib got address */
6166         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
6167         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6168         /* arch_emit_got_access () patches this */
6169         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0xf0f0f0f0, 4);
6170
6171         return code;
6172 }
6173
6174 /* Can't put this into mini-x86.h */
6175 gpointer
6176 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot);
6177
6178 GSList *
6179 mono_arch_get_trampolines (gboolean aot)
6180 {
6181         MonoTrampInfo *info;
6182         GSList *tramps = NULL;
6183
6184         mono_x86_get_signal_exception_trampoline (&info, aot);
6185
6186         tramps = g_slist_append (tramps, info);
6187
6188         return tramps;
6189 }
6190
6191
6192 #if __APPLE__
6193 #define DBG_SIGNAL SIGBUS
6194 #else
6195 #define DBG_SIGNAL SIGSEGV
6196 #endif
6197
6198 /* Soft Debug support */
6199 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6200
6201 /*
6202  * mono_arch_set_breakpoint:
6203  *
6204  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
6205  * The location should contain code emitted by OP_SEQ_POINT.
6206  */
6207 void
6208 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6209 {
6210         guint8 *code = ip;
6211
6212         /* 
6213          * In production, we will use int3 (has to fix the size in the md 
6214          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
6215          * instead.
6216          */
6217         g_assert (code [0] == 0x90);
6218         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
6219 }
6220
6221 /*
6222  * mono_arch_clear_breakpoint:
6223  *
6224  *   Clear the breakpoint at IP.
6225  */
6226 void
6227 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6228 {
6229         guint8 *code = ip;
6230         int i;
6231
6232         for (i = 0; i < 6; ++i)
6233                 x86_nop (code);
6234 }
6235         
6236 /*
6237  * mono_arch_start_single_stepping:
6238  *
6239  *   Start single stepping.
6240  */
6241 void
6242 mono_arch_start_single_stepping (void)
6243 {
6244         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6245 }
6246         
6247 /*
6248  * mono_arch_stop_single_stepping:
6249  *
6250  *   Stop single stepping.
6251  */
6252 void
6253 mono_arch_stop_single_stepping (void)
6254 {
6255         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6256 }
6257
6258 /*
6259  * mono_arch_is_single_step_event:
6260  *
6261  *   Return whenever the machine state in SIGCTX corresponds to a single
6262  * step event.
6263  */
6264 gboolean
6265 mono_arch_is_single_step_event (void *info, void *sigctx)
6266 {
6267 #ifdef TARGET_WIN32
6268         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
6269         if ((einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
6270                 return TRUE;
6271         else
6272                 return FALSE;
6273 #else
6274         siginfo_t* sinfo = (siginfo_t*) info;
6275         /* Sometimes the address is off by 4 */
6276         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
6277                 return TRUE;
6278         else
6279                 return FALSE;
6280 #endif
6281 }
6282
6283 gboolean
6284 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6285 {
6286 #ifdef TARGET_WIN32
6287         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
6288         if ((einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
6289                 return TRUE;
6290         else
6291                 return FALSE;
6292 #else
6293         siginfo_t* sinfo = (siginfo_t*)info;
6294         /* Sometimes the address is off by 4 */
6295         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
6296                 return TRUE;
6297         else
6298                 return FALSE;
6299 #endif
6300 }
6301
6302 /*
6303  * mono_arch_get_ip_for_breakpoint:
6304  *
6305  *   See mini-amd64.c for docs.
6306  */
6307 guint8*
6308 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6309 {
6310         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6311
6312         return ip;
6313 }
6314
6315 #define BREAKPOINT_SIZE 6
6316
6317 /*
6318  * mono_arch_get_ip_for_single_step:
6319  *
6320  *   See mini-amd64.c for docs.
6321  */
6322 guint8*
6323 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6324 {
6325         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6326
6327         /* Size of x86_alu_reg_imm */
6328         ip += 6;
6329
6330         return ip;
6331 }
6332
6333 /*
6334  * mono_arch_skip_breakpoint:
6335  *
6336  *   See mini-amd64.c for docs.
6337  */
6338 void
6339 mono_arch_skip_breakpoint (MonoContext *ctx)
6340 {
6341         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6342 }
6343
6344 /*
6345  * mono_arch_skip_single_step:
6346  *
6347  *   See mini-amd64.c for docs.
6348  */
6349 void
6350 mono_arch_skip_single_step (MonoContext *ctx)
6351 {
6352         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
6353 }
6354
6355 /*
6356  * mono_arch_get_seq_point_info:
6357  *
6358  *   See mini-amd64.c for docs.
6359  */
6360 gpointer
6361 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6362 {
6363         NOT_IMPLEMENTED;
6364         return NULL;
6365 }
6366
6367 #endif
6368