Merge branch 'marek'
[mono.git] / mono / mini / mini-x86.c
1 /*
2  * mini-x86.c: x86 backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Patrik Torstensson
8  *
9  * (C) 2003 Ximian, Inc.
10  */
11 #include "mini.h"
12 #include <string.h>
13 #include <math.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/mono-debug.h>
23 #include <mono/metadata/gc-internal.h>
24 #include <mono/utils/mono-math.h>
25 #include <mono/utils/mono-counters.h>
26 #include <mono/utils/mono-mmap.h>
27
28 #include "trace.h"
29 #include "mini-x86.h"
30 #include "cpu-x86.h"
31 #include "ir-emit.h"
32
33 /* On windows, these hold the key returned by TlsAlloc () */
34 static gint lmf_tls_offset = -1;
35 static gint lmf_addr_tls_offset = -1;
36 static gint appdomain_tls_offset = -1;
37
38 #ifdef MONO_XEN_OPT
39 static gboolean optimize_for_xen = TRUE;
40 #else
41 #define optimize_for_xen 0
42 #endif
43
44 #ifdef TARGET_WIN32
45 static gboolean is_win32 = TRUE;
46 #else
47 static gboolean is_win32 = FALSE;
48 #endif
49
50 /* This mutex protects architecture specific caches */
51 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
52 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
53 static CRITICAL_SECTION mini_arch_mutex;
54
55 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
56
57 #define ARGS_OFFSET 8
58
59 #ifdef TARGET_WIN32
60 /* Under windows, the default pinvoke calling convention is stdcall */
61 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
62 #else
63 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
64 #endif
65
66 MonoBreakpointInfo
67 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
68
69 static gpointer
70 mono_realloc_native_code (MonoCompile *cfg)
71 {
72 #ifdef __native_client_codegen__
73         guint old_padding;
74         gpointer native_code;
75         guint alignment_check;
76
77         /* Save the old alignment offset so we can re-align after the realloc. */
78         old_padding = (guint)(cfg->native_code - cfg->native_code_alloc);
79
80         cfg->native_code_alloc = g_realloc (cfg->native_code_alloc, 
81                                                                                 cfg->code_size + kNaClAlignment);
82
83         /* Align native_code to next nearest kNaClAlignment byte. */
84         native_code = (guint)cfg->native_code_alloc + kNaClAlignment;
85         native_code = (guint)native_code & ~kNaClAlignmentMask;
86
87         /* Shift the data to be 32-byte aligned again. */
88         memmove (native_code, cfg->native_code_alloc + old_padding, cfg->code_size);
89
90         alignment_check = (guint)native_code & kNaClAlignmentMask;
91         g_assert (alignment_check == 0);
92         return native_code;
93 #else
94         return g_realloc (cfg->native_code, cfg->code_size);
95 #endif
96 }
97
98 #ifdef __native_client_codegen__
99
100 /* mono_arch_nacl_pad: Add pad bytes of alignment instructions at code,       */
101 /* Check that alignment doesn't cross an alignment boundary.        */
102 guint8 *
103 mono_arch_nacl_pad (guint8 *code, int pad)
104 {
105         const int kMaxPadding = 7;    /* see x86-codegen.h: x86_padding() */
106
107         if (pad == 0) return code;
108         /* assertion: alignment cannot cross a block boundary */
109         g_assert(((uintptr_t)code & (~kNaClAlignmentMask)) ==
110                          (((uintptr_t)code + pad - 1) & (~kNaClAlignmentMask)));
111         while (pad >= kMaxPadding) {
112                 x86_padding (code, kMaxPadding);
113                 pad -= kMaxPadding;
114         }
115         if (pad != 0) x86_padding (code, pad);
116         return code;
117 }
118
119 guint8 *
120 mono_arch_nacl_skip_nops (guint8 *code)
121 {
122         x86_skip_nops (code);
123         return code;
124 }
125
126 #endif /* __native_client_codegen__ */
127
128 /*
129  * The code generated for sequence points reads from this location, which is
130  * made read-only when single stepping is enabled.
131  */
132 static gpointer ss_trigger_page;
133
134 /* Enabled breakpoints read from this trigger page */
135 static gpointer bp_trigger_page;
136
137 const char*
138 mono_arch_regname (int reg)
139 {
140         switch (reg) {
141         case X86_EAX: return "%eax";
142         case X86_EBX: return "%ebx";
143         case X86_ECX: return "%ecx";
144         case X86_EDX: return "%edx";
145         case X86_ESP: return "%esp";    
146         case X86_EBP: return "%ebp";
147         case X86_EDI: return "%edi";
148         case X86_ESI: return "%esi";
149         }
150         return "unknown";
151 }
152
153 const char*
154 mono_arch_fregname (int reg)
155 {
156         switch (reg) {
157         case 0:
158                 return "%fr0";
159         case 1:
160                 return "%fr1";
161         case 2:
162                 return "%fr2";
163         case 3:
164                 return "%fr3";
165         case 4:
166                 return "%fr4";
167         case 5:
168                 return "%fr5";
169         case 6:
170                 return "%fr6";
171         case 7:
172                 return "%fr7";
173         default:
174                 return "unknown";
175         }
176 }
177
178 const char *
179 mono_arch_xregname (int reg)
180 {
181         switch (reg) {
182         case 0:
183                 return "%xmm0";
184         case 1:
185                 return "%xmm1";
186         case 2:
187                 return "%xmm2";
188         case 3:
189                 return "%xmm3";
190         case 4:
191                 return "%xmm4";
192         case 5:
193                 return "%xmm5";
194         case 6:
195                 return "%xmm6";
196         case 7:
197                 return "%xmm7";
198         default:
199                 return "unknown";
200         }
201 }
202
203 void 
204 mono_x86_patch (unsigned char* code, gpointer target)
205 {
206         x86_patch (code, (unsigned char*)target);
207 }
208
209 typedef enum {
210         ArgInIReg,
211         ArgInFloatSSEReg,
212         ArgInDoubleSSEReg,
213         ArgOnStack,
214         ArgValuetypeInReg,
215         ArgOnFloatFpStack,
216         ArgOnDoubleFpStack,
217         ArgNone
218 } ArgStorage;
219
220 typedef struct {
221         gint16 offset;
222         gint8  reg;
223         ArgStorage storage;
224
225         /* Only if storage == ArgValuetypeInReg */
226         ArgStorage pair_storage [2];
227         gint8 pair_regs [2];
228 } ArgInfo;
229
230 typedef struct {
231         int nargs;
232         guint32 stack_usage;
233         guint32 reg_usage;
234         guint32 freg_usage;
235         gboolean need_stack_align;
236         guint32 stack_align_amount;
237         gboolean vtype_retaddr;
238         /* The index of the vret arg in the argument list */
239         int vret_arg_index;
240         ArgInfo ret;
241         ArgInfo sig_cookie;
242         ArgInfo args [1];
243 } CallInfo;
244
245 #define PARAM_REGS 0
246
247 #define FLOAT_PARAM_REGS 0
248
249 static X86_Reg_No param_regs [] = { 0 };
250
251 #if defined(TARGET_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
252 #define SMALL_STRUCTS_IN_REGS
253 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
254 #endif
255
256 static void inline
257 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
258 {
259     ainfo->offset = *stack_size;
260
261     if (*gr >= PARAM_REGS) {
262                 ainfo->storage = ArgOnStack;
263                 (*stack_size) += sizeof (gpointer);
264     }
265     else {
266                 ainfo->storage = ArgInIReg;
267                 ainfo->reg = param_regs [*gr];
268                 (*gr) ++;
269     }
270 }
271
272 static void inline
273 add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
274 {
275         ainfo->offset = *stack_size;
276
277         g_assert (PARAM_REGS == 0);
278         
279         ainfo->storage = ArgOnStack;
280         (*stack_size) += sizeof (gpointer) * 2;
281 }
282
283 static void inline
284 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
285 {
286     ainfo->offset = *stack_size;
287
288     if (*gr >= FLOAT_PARAM_REGS) {
289                 ainfo->storage = ArgOnStack;
290                 (*stack_size) += is_double ? 8 : 4;
291     }
292     else {
293                 /* A double register */
294                 if (is_double)
295                         ainfo->storage = ArgInDoubleSSEReg;
296                 else
297                         ainfo->storage = ArgInFloatSSEReg;
298                 ainfo->reg = *gr;
299                 (*gr) += 1;
300     }
301 }
302
303
304 static void
305 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
306                gboolean is_return,
307                guint32 *gr, guint32 *fr, guint32 *stack_size)
308 {
309         guint32 size;
310         MonoClass *klass;
311
312         klass = mono_class_from_mono_type (type);
313         size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
314
315 #ifdef SMALL_STRUCTS_IN_REGS
316         if (sig->pinvoke && is_return) {
317                 MonoMarshalType *info;
318
319                 /*
320                  * the exact rules are not very well documented, the code below seems to work with the 
321                  * code generated by gcc 3.3.3 -mno-cygwin.
322                  */
323                 info = mono_marshal_load_type_info (klass);
324                 g_assert (info);
325
326                 ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
327
328                 /* Special case structs with only a float member */
329                 if ((info->native_size == 8) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R8)) {
330                         ainfo->storage = ArgValuetypeInReg;
331                         ainfo->pair_storage [0] = ArgOnDoubleFpStack;
332                         return;
333                 }
334                 if ((info->native_size == 4) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R4)) {
335                         ainfo->storage = ArgValuetypeInReg;
336                         ainfo->pair_storage [0] = ArgOnFloatFpStack;
337                         return;
338                 }               
339                 if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
340                         ainfo->storage = ArgValuetypeInReg;
341                         ainfo->pair_storage [0] = ArgInIReg;
342                         ainfo->pair_regs [0] = return_regs [0];
343                         if (info->native_size > 4) {
344                                 ainfo->pair_storage [1] = ArgInIReg;
345                                 ainfo->pair_regs [1] = return_regs [1];
346                         }
347                         return;
348                 }
349         }
350 #endif
351
352         ainfo->offset = *stack_size;
353         ainfo->storage = ArgOnStack;
354         *stack_size += ALIGN_TO (size, sizeof (gpointer));
355 }
356
357 /*
358  * get_call_info:
359  *
360  *  Obtain information about a call according to the calling convention.
361  * For x86 ELF, see the "System V Application Binary Interface Intel386 
362  * Architecture Processor Supplment, Fourth Edition" document for more
363  * information.
364  * For x86 win32, see ???.
365  */
366 static CallInfo*
367 get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig, gboolean is_pinvoke)
368 {
369         guint32 i, gr, fr, pstart;
370         MonoType *ret_type;
371         int n = sig->hasthis + sig->param_count;
372         guint32 stack_size = 0;
373
374         gr = 0;
375         fr = 0;
376
377         /* return value */
378         {
379                 ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
380                 switch (ret_type->type) {
381                 case MONO_TYPE_BOOLEAN:
382                 case MONO_TYPE_I1:
383                 case MONO_TYPE_U1:
384                 case MONO_TYPE_I2:
385                 case MONO_TYPE_U2:
386                 case MONO_TYPE_CHAR:
387                 case MONO_TYPE_I4:
388                 case MONO_TYPE_U4:
389                 case MONO_TYPE_I:
390                 case MONO_TYPE_U:
391                 case MONO_TYPE_PTR:
392                 case MONO_TYPE_FNPTR:
393                 case MONO_TYPE_CLASS:
394                 case MONO_TYPE_OBJECT:
395                 case MONO_TYPE_SZARRAY:
396                 case MONO_TYPE_ARRAY:
397                 case MONO_TYPE_STRING:
398                         cinfo->ret.storage = ArgInIReg;
399                         cinfo->ret.reg = X86_EAX;
400                         break;
401                 case MONO_TYPE_U8:
402                 case MONO_TYPE_I8:
403                         cinfo->ret.storage = ArgInIReg;
404                         cinfo->ret.reg = X86_EAX;
405                         break;
406                 case MONO_TYPE_R4:
407                         cinfo->ret.storage = ArgOnFloatFpStack;
408                         break;
409                 case MONO_TYPE_R8:
410                         cinfo->ret.storage = ArgOnDoubleFpStack;
411                         break;
412                 case MONO_TYPE_GENERICINST:
413                         if (!mono_type_generic_inst_is_valuetype (ret_type)) {
414                                 cinfo->ret.storage = ArgInIReg;
415                                 cinfo->ret.reg = X86_EAX;
416                                 break;
417                         }
418                         /* Fall through */
419                 case MONO_TYPE_VALUETYPE: {
420                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
421
422                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
423                         if (cinfo->ret.storage == ArgOnStack) {
424                                 cinfo->vtype_retaddr = TRUE;
425                                 /* The caller passes the address where the value is stored */
426                         }
427                         break;
428                 }
429                 case MONO_TYPE_TYPEDBYREF:
430                         /* Same as a valuetype with size 12 */
431                         cinfo->vtype_retaddr = TRUE;
432                         break;
433                 case MONO_TYPE_VOID:
434                         cinfo->ret.storage = ArgNone;
435                         break;
436                 default:
437                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
438                 }
439         }
440
441         pstart = 0;
442         /*
443          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
444          * the first argument, allowing 'this' to be always passed in the first arg reg.
445          * Also do this if the first argument is a reference type, since virtual calls
446          * are sometimes made using calli without sig->hasthis set, like in the delegate
447          * invoke wrappers.
448          */
449         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
450                 if (sig->hasthis) {
451                         add_general (&gr, &stack_size, cinfo->args + 0);
452                 } else {
453                         add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
454                         pstart = 1;
455                 }
456                 add_general (&gr, &stack_size, &cinfo->ret);
457                 cinfo->vret_arg_index = 1;
458         } else {
459                 /* this */
460                 if (sig->hasthis)
461                         add_general (&gr, &stack_size, cinfo->args + 0);
462
463                 if (cinfo->vtype_retaddr)
464                         add_general (&gr, &stack_size, &cinfo->ret);
465         }
466
467         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
468                 gr = PARAM_REGS;
469                 fr = FLOAT_PARAM_REGS;
470                 
471                 /* Emit the signature cookie just before the implicit arguments */
472                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
473         }
474
475         for (i = pstart; i < sig->param_count; ++i) {
476                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
477                 MonoType *ptype;
478
479                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
480                         /* We allways pass the sig cookie on the stack for simplicity */
481                         /* 
482                          * Prevent implicit arguments + the sig cookie from being passed 
483                          * in registers.
484                          */
485                         gr = PARAM_REGS;
486                         fr = FLOAT_PARAM_REGS;
487
488                         /* Emit the signature cookie just before the implicit arguments */
489                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
490                 }
491
492                 if (sig->params [i]->byref) {
493                         add_general (&gr, &stack_size, ainfo);
494                         continue;
495                 }
496                 ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
497                 switch (ptype->type) {
498                 case MONO_TYPE_BOOLEAN:
499                 case MONO_TYPE_I1:
500                 case MONO_TYPE_U1:
501                         add_general (&gr, &stack_size, ainfo);
502                         break;
503                 case MONO_TYPE_I2:
504                 case MONO_TYPE_U2:
505                 case MONO_TYPE_CHAR:
506                         add_general (&gr, &stack_size, ainfo);
507                         break;
508                 case MONO_TYPE_I4:
509                 case MONO_TYPE_U4:
510                         add_general (&gr, &stack_size, ainfo);
511                         break;
512                 case MONO_TYPE_I:
513                 case MONO_TYPE_U:
514                 case MONO_TYPE_PTR:
515                 case MONO_TYPE_FNPTR:
516                 case MONO_TYPE_CLASS:
517                 case MONO_TYPE_OBJECT:
518                 case MONO_TYPE_STRING:
519                 case MONO_TYPE_SZARRAY:
520                 case MONO_TYPE_ARRAY:
521                         add_general (&gr, &stack_size, ainfo);
522                         break;
523                 case MONO_TYPE_GENERICINST:
524                         if (!mono_type_generic_inst_is_valuetype (ptype)) {
525                                 add_general (&gr, &stack_size, ainfo);
526                                 break;
527                         }
528                         /* Fall through */
529                 case MONO_TYPE_VALUETYPE:
530                         add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
531                         break;
532                 case MONO_TYPE_TYPEDBYREF:
533                         stack_size += sizeof (MonoTypedRef);
534                         ainfo->storage = ArgOnStack;
535                         break;
536                 case MONO_TYPE_U8:
537                 case MONO_TYPE_I8:
538                         add_general_pair (&gr, &stack_size, ainfo);
539                         break;
540                 case MONO_TYPE_R4:
541                         add_float (&fr, &stack_size, ainfo, FALSE);
542                         break;
543                 case MONO_TYPE_R8:
544                         add_float (&fr, &stack_size, ainfo, TRUE);
545                         break;
546                 default:
547                         g_error ("unexpected type 0x%x", ptype->type);
548                         g_assert_not_reached ();
549                 }
550         }
551
552         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
553                 gr = PARAM_REGS;
554                 fr = FLOAT_PARAM_REGS;
555                 
556                 /* Emit the signature cookie just before the implicit arguments */
557                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
558         }
559
560         if (mono_do_x86_stack_align && (stack_size % MONO_ARCH_FRAME_ALIGNMENT) != 0) {
561                 cinfo->need_stack_align = TRUE;
562                 cinfo->stack_align_amount = MONO_ARCH_FRAME_ALIGNMENT - (stack_size % MONO_ARCH_FRAME_ALIGNMENT);
563                 stack_size += cinfo->stack_align_amount;
564         }
565
566         cinfo->stack_usage = stack_size;
567         cinfo->reg_usage = gr;
568         cinfo->freg_usage = fr;
569         return cinfo;
570 }
571
572 static CallInfo*
573 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
574 {
575         int n = sig->hasthis + sig->param_count;
576         CallInfo *cinfo;
577
578         if (mp)
579                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
580         else
581                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
582
583         return get_call_info_internal (gsctx, cinfo, sig, is_pinvoke);
584 }
585
586 /*
587  * mono_arch_get_argument_info:
588  * @csig:  a method signature
589  * @param_count: the number of parameters to consider
590  * @arg_info: an array to store the result infos
591  *
592  * Gathers information on parameters such as size, alignment and
593  * padding. arg_info should be large enought to hold param_count + 1 entries. 
594  *
595  * Returns the size of the argument area on the stack.
596  * This should be signal safe, since it is called from
597  * mono_arch_find_jit_info_ext ().
598  * FIXME: The metadata calls might not be signal safe.
599  */
600 int
601 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
602 {
603         int len, k, args_size = 0;
604         int size, pad;
605         guint32 align;
606         int offset = 8;
607         CallInfo *cinfo;
608
609         /* Avoid g_malloc as it is not signal safe */
610         len = sizeof (CallInfo) + (sizeof (ArgInfo) * (csig->param_count + 1));
611         cinfo = (CallInfo*)g_newa (guint8*, len);
612         memset (cinfo, 0, len);
613
614         cinfo = get_call_info_internal (NULL, cinfo, csig, FALSE);
615
616         arg_info [0].offset = offset;
617
618         if (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 (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                         x86_mov_membase_imm (code, X86_EDX, card_table, 1, 1);
4058                         x86_patch (br, code);
4059                         break;
4060                 }
4061 #endif
4062 #ifdef MONO_ARCH_SIMD_INTRINSICS
4063                 case OP_ADDPS:
4064                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4065                         break;
4066                 case OP_DIVPS:
4067                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4068                         break;
4069                 case OP_MULPS:
4070                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4071                         break;
4072                 case OP_SUBPS:
4073                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4074                         break;
4075                 case OP_MAXPS:
4076                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4077                         break;
4078                 case OP_MINPS:
4079                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4080                         break;
4081                 case OP_COMPPS:
4082                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4083                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4084                         break;
4085                 case OP_ANDPS:
4086                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4087                         break;
4088                 case OP_ANDNPS:
4089                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4090                         break;
4091                 case OP_ORPS:
4092                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4093                         break;
4094                 case OP_XORPS:
4095                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4096                         break;
4097                 case OP_SQRTPS:
4098                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4099                         break;
4100                 case OP_RSQRTPS:
4101                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
4102                         break;
4103                 case OP_RCPPS:
4104                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
4105                         break;
4106                 case OP_ADDSUBPS:
4107                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4108                         break;
4109                 case OP_HADDPS:
4110                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4111                         break;
4112                 case OP_HSUBPS:
4113                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4114                         break;
4115                 case OP_DUPPS_HIGH:
4116                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
4117                         break;
4118                 case OP_DUPPS_LOW:
4119                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
4120                         break;
4121
4122                 case OP_PSHUFLEW_HIGH:
4123                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4124                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
4125                         break;
4126                 case OP_PSHUFLEW_LOW:
4127                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4128                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
4129                         break;
4130                 case OP_PSHUFLED:
4131                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4132                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
4133                         break;
4134
4135                 case OP_ADDPD:
4136                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4137                         break;
4138                 case OP_DIVPD:
4139                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4140                         break;
4141                 case OP_MULPD:
4142                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4143                         break;
4144                 case OP_SUBPD:
4145                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4146                         break;
4147                 case OP_MAXPD:
4148                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4149                         break;
4150                 case OP_MINPD:
4151                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4152                         break;
4153                 case OP_COMPPD:
4154                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4155                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4156                         break;
4157                 case OP_ANDPD:
4158                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4159                         break;
4160                 case OP_ANDNPD:
4161                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4162                         break;
4163                 case OP_ORPD:
4164                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4165                         break;
4166                 case OP_XORPD:
4167                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4168                         break;
4169                 case OP_SQRTPD:
4170                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4171                         break;
4172                 case OP_ADDSUBPD:
4173                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4174                         break;
4175                 case OP_HADDPD:
4176                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4177                         break;
4178                 case OP_HSUBPD:
4179                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4180                         break;
4181                 case OP_DUPPD:
4182                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
4183                         break;
4184                         
4185                 case OP_EXTRACT_MASK:
4186                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
4187                         break;
4188         
4189                 case OP_PAND:
4190                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
4191                         break;
4192                 case OP_POR:
4193                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
4194                         break;
4195                 case OP_PXOR:
4196                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
4197                         break;
4198
4199                 case OP_PADDB:
4200                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
4201                         break;
4202                 case OP_PADDW:
4203                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
4204                         break;
4205                 case OP_PADDD:
4206                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
4207                         break;
4208                 case OP_PADDQ:
4209                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
4210                         break;
4211
4212                 case OP_PSUBB:
4213                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
4214                         break;
4215                 case OP_PSUBW:
4216                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
4217                         break;
4218                 case OP_PSUBD:
4219                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
4220                         break;
4221                 case OP_PSUBQ:
4222                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
4223                         break;
4224
4225                 case OP_PMAXB_UN:
4226                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
4227                         break;
4228                 case OP_PMAXW_UN:
4229                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
4230                         break;
4231                 case OP_PMAXD_UN:
4232                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
4233                         break;
4234                 
4235                 case OP_PMAXB:
4236                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
4237                         break;
4238                 case OP_PMAXW:
4239                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
4240                         break;
4241                 case OP_PMAXD:
4242                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4243                         break;
4244
4245                 case OP_PAVGB_UN:
4246                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4247                         break;
4248                 case OP_PAVGW_UN:
4249                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4250                         break;
4251
4252                 case OP_PMINB_UN:
4253                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4254                         break;
4255                 case OP_PMINW_UN:
4256                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4257                         break;
4258                 case OP_PMIND_UN:
4259                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4260                         break;
4261
4262                 case OP_PMINB:
4263                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4264                         break;
4265                 case OP_PMINW:
4266                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4267                         break;
4268                 case OP_PMIND:
4269                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4270                         break;
4271
4272                 case OP_PCMPEQB:
4273                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4274                         break;
4275                 case OP_PCMPEQW:
4276                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4277                         break;
4278                 case OP_PCMPEQD:
4279                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4280                         break;
4281                 case OP_PCMPEQQ:
4282                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4283                         break;
4284
4285                 case OP_PCMPGTB:
4286                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4287                         break;
4288                 case OP_PCMPGTW:
4289                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4290                         break;
4291                 case OP_PCMPGTD:
4292                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4293                         break;
4294                 case OP_PCMPGTQ:
4295                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4296                         break;
4297
4298                 case OP_PSUM_ABS_DIFF:
4299                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4300                         break;
4301
4302                 case OP_UNPACK_LOWB:
4303                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4304                         break;
4305                 case OP_UNPACK_LOWW:
4306                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4307                         break;
4308                 case OP_UNPACK_LOWD:
4309                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4310                         break;
4311                 case OP_UNPACK_LOWQ:
4312                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4313                         break;
4314                 case OP_UNPACK_LOWPS:
4315                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4316                         break;
4317                 case OP_UNPACK_LOWPD:
4318                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4319                         break;
4320
4321                 case OP_UNPACK_HIGHB:
4322                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4323                         break;
4324                 case OP_UNPACK_HIGHW:
4325                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4326                         break;
4327                 case OP_UNPACK_HIGHD:
4328                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4329                         break;
4330                 case OP_UNPACK_HIGHQ:
4331                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4332                         break;
4333                 case OP_UNPACK_HIGHPS:
4334                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4335                         break;
4336                 case OP_UNPACK_HIGHPD:
4337                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4338                         break;
4339
4340                 case OP_PACKW:
4341                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4342                         break;
4343                 case OP_PACKD:
4344                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4345                         break;
4346                 case OP_PACKW_UN:
4347                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4348                         break;
4349                 case OP_PACKD_UN:
4350                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4351                         break;
4352
4353                 case OP_PADDB_SAT_UN:
4354                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4355                         break;
4356                 case OP_PSUBB_SAT_UN:
4357                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4358                         break;
4359                 case OP_PADDW_SAT_UN:
4360                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4361                         break;
4362                 case OP_PSUBW_SAT_UN:
4363                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4364                         break;
4365
4366                 case OP_PADDB_SAT:
4367                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4368                         break;
4369                 case OP_PSUBB_SAT:
4370                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4371                         break;
4372                 case OP_PADDW_SAT:
4373                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4374                         break;
4375                 case OP_PSUBW_SAT:
4376                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4377                         break;
4378                         
4379                 case OP_PMULW:
4380                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4381                         break;
4382                 case OP_PMULD:
4383                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4384                         break;
4385                 case OP_PMULQ:
4386                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4387                         break;
4388                 case OP_PMULW_HIGH_UN:
4389                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4390                         break;
4391                 case OP_PMULW_HIGH:
4392                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4393                         break;
4394
4395                 case OP_PSHRW:
4396                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4397                         break;
4398                 case OP_PSHRW_REG:
4399                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4400                         break;
4401
4402                 case OP_PSARW:
4403                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4404                         break;
4405                 case OP_PSARW_REG:
4406                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4407                         break;
4408
4409                 case OP_PSHLW:
4410                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4411                         break;
4412                 case OP_PSHLW_REG:
4413                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4414                         break;
4415
4416                 case OP_PSHRD:
4417                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4418                         break;
4419                 case OP_PSHRD_REG:
4420                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4421                         break;
4422
4423                 case OP_PSARD:
4424                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4425                         break;
4426                 case OP_PSARD_REG:
4427                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4428                         break;
4429
4430                 case OP_PSHLD:
4431                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4432                         break;
4433                 case OP_PSHLD_REG:
4434                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4435                         break;
4436
4437                 case OP_PSHRQ:
4438                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4439                         break;
4440                 case OP_PSHRQ_REG:
4441                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4442                         break;
4443
4444                 case OP_PSHLQ:
4445                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4446                         break;
4447                 case OP_PSHLQ_REG:
4448                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4449                         break;          
4450                         
4451                 case OP_ICONV_TO_X:
4452                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4453                         break;
4454                 case OP_EXTRACT_I4:
4455                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4456                         break;
4457                 case OP_EXTRACT_I1:
4458                 case OP_EXTRACT_U1:
4459                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4460                         if (ins->inst_c0)
4461                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4462                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4463                         break;
4464                 case OP_EXTRACT_I2:
4465                 case OP_EXTRACT_U2:
4466                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4467                         if (ins->inst_c0)
4468                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4469                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4470                         break;
4471                 case OP_EXTRACT_R8:
4472                         if (ins->inst_c0)
4473                                 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);
4474                         else
4475                                 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);
4476                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4477                         break;
4478
4479                 case OP_INSERT_I2:
4480                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4481                         break;
4482                 case OP_EXTRACTX_U2:
4483                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4484                         break;
4485                 case OP_INSERTX_U1_SLOW:
4486                         /*sreg1 is the extracted ireg (scratch)
4487                         /sreg2 is the to be inserted ireg (scratch)
4488                         /dreg is the xreg to receive the value*/
4489
4490                         /*clear the bits from the extracted word*/
4491                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4492                         /*shift the value to insert if needed*/
4493                         if (ins->inst_c0 & 1)
4494                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4495                         /*join them together*/
4496                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4497                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4498                         break;
4499                 case OP_INSERTX_I4_SLOW:
4500                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4501                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4502                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4503                         break;
4504
4505                 case OP_INSERTX_R4_SLOW:
4506                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4507                         /*TODO if inst_c0 == 0 use movss*/
4508                         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);
4509                         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);
4510                         break;
4511                 case OP_INSERTX_R8_SLOW:
4512                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4513                         if (ins->inst_c0)
4514                                 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);
4515                         else
4516                                 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);
4517                         break;
4518
4519                 case OP_STOREX_MEMBASE_REG:
4520                 case OP_STOREX_MEMBASE:
4521                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4522                         break;
4523                 case OP_LOADX_MEMBASE:
4524                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4525                         break;
4526                 case OP_LOADX_ALIGNED_MEMBASE:
4527                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4528                         break;
4529                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4530                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4531                         break;
4532                 case OP_STOREX_NTA_MEMBASE_REG:
4533                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4534                         break;
4535                 case OP_PREFETCH_MEMBASE:
4536                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4537
4538                         break;
4539                 case OP_XMOVE:
4540                         /*FIXME the peephole pass should have killed this*/
4541                         if (ins->dreg != ins->sreg1)
4542                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4543                         break;          
4544                 case OP_XZERO:
4545                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4546                         break;
4547                 case OP_ICONV_TO_R8_RAW:
4548                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4549                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4550                         break;
4551
4552                 case OP_FCONV_TO_R8_X:
4553                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4554                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4555                         break;
4556
4557                 case OP_XCONV_R8_TO_I4:
4558                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4559                         switch (ins->backend.source_opcode) {
4560                         case OP_FCONV_TO_I1:
4561                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4562                                 break;
4563                         case OP_FCONV_TO_U1:
4564                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4565                                 break;
4566                         case OP_FCONV_TO_I2:
4567                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4568                                 break;
4569                         case OP_FCONV_TO_U2:
4570                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4571                                 break;
4572                         }                       
4573                         break;
4574
4575                 case OP_EXPAND_I1:
4576                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4577                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4578                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4579                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4580                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4581                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4582                         break;
4583                 case OP_EXPAND_I2:
4584                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4585                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4586                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4587                         break;
4588                 case OP_EXPAND_I4:
4589                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4590                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4591                         break;
4592                 case OP_EXPAND_R4:
4593                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4594                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4595                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4596                         break;
4597                 case OP_EXPAND_R8:
4598                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4599                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4600                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4601                         break;
4602 #endif
4603                 case OP_LIVERANGE_START: {
4604                         if (cfg->verbose_level > 1)
4605                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4606                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4607                         break;
4608                 }
4609                 case OP_LIVERANGE_END: {
4610                         if (cfg->verbose_level > 1)
4611                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4612                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4613                         break;
4614                 }
4615                 default:
4616                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
4617                         g_assert_not_reached ();
4618                 }
4619
4620                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
4621 #ifndef __native_client_codegen__
4622                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4623                                            mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4624                         g_assert_not_reached ();
4625 #endif  /* __native_client_codegen__ */
4626                 }
4627                
4628                 cpos += max_len;
4629         }
4630
4631         cfg->code_len = code - cfg->native_code;
4632 }
4633
4634 #endif /* DISABLE_JIT */
4635
4636 void
4637 mono_arch_register_lowlevel_calls (void)
4638 {
4639 }
4640
4641 void
4642 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4643 {
4644         MonoJumpInfo *patch_info;
4645         gboolean compile_aot = !run_cctors;
4646
4647         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4648                 unsigned char *ip = patch_info->ip.i + code;
4649                 const unsigned char *target;
4650
4651                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4652
4653                 if (compile_aot) {
4654                         switch (patch_info->type) {
4655                         case MONO_PATCH_INFO_BB:
4656                         case MONO_PATCH_INFO_LABEL:
4657                                 break;
4658                         default:
4659                                 /* No need to patch these */
4660                                 continue;
4661                         }
4662                 }
4663
4664                 switch (patch_info->type) {
4665                 case MONO_PATCH_INFO_IP:
4666                         *((gconstpointer *)(ip)) = target;
4667                         break;
4668                 case MONO_PATCH_INFO_CLASS_INIT: {
4669                         guint8 *code = ip;
4670                         /* Might already been changed to a nop */
4671                         x86_call_code (code, 0);
4672                         x86_patch (ip, target);
4673                         break;
4674                 }
4675                 case MONO_PATCH_INFO_ABS:
4676                 case MONO_PATCH_INFO_METHOD:
4677                 case MONO_PATCH_INFO_METHOD_JUMP:
4678                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4679                 case MONO_PATCH_INFO_BB:
4680                 case MONO_PATCH_INFO_LABEL:
4681                 case MONO_PATCH_INFO_RGCTX_FETCH:
4682                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
4683                 case MONO_PATCH_INFO_MONITOR_ENTER:
4684                 case MONO_PATCH_INFO_MONITOR_EXIT:
4685                         x86_patch (ip, target);
4686                         break;
4687                 case MONO_PATCH_INFO_NONE:
4688                         break;
4689                 default: {
4690                         guint32 offset = mono_arch_get_patch_offset (ip);
4691                         *((gconstpointer *)(ip + offset)) = target;
4692                         break;
4693                 }
4694                 }
4695         }
4696 }
4697
4698 guint8 *
4699 mono_arch_emit_prolog (MonoCompile *cfg)
4700 {
4701         MonoMethod *method = cfg->method;
4702         MonoBasicBlock *bb;
4703         MonoMethodSignature *sig;
4704         MonoInst *inst;
4705         int alloc_size, pos, max_offset, i, cfa_offset;
4706         guint8 *code;
4707         gboolean need_stack_frame;
4708 #ifdef __native_client_codegen__
4709         guint alignment_check;
4710 #endif
4711
4712         cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
4713
4714         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4715                 cfg->code_size += 512;
4716
4717 #ifdef __native_client_codegen__
4718         /* native_code_alloc is not 32-byte aligned, native_code is. */
4719         cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment);
4720
4721         /* Align native_code to next nearest kNaclAlignment byte. */
4722         cfg->native_code = (guint)cfg->native_code_alloc + kNaClAlignment; 
4723         cfg->native_code = (guint)cfg->native_code & ~kNaClAlignmentMask;
4724         
4725         code = cfg->native_code;
4726
4727         alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
4728         g_assert(alignment_check == 0);
4729 #else
4730         code = cfg->native_code = g_malloc (cfg->code_size);
4731 #endif
4732
4733         /* Offset between RSP and the CFA */
4734         cfa_offset = 0;
4735
4736         // CFA = sp + 4
4737         cfa_offset = sizeof (gpointer);
4738         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
4739         // IP saved at CFA - 4
4740         /* There is no IP reg on x86 */
4741         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
4742
4743         need_stack_frame = needs_stack_frame (cfg);
4744
4745         if (need_stack_frame) {
4746                 x86_push_reg (code, X86_EBP);
4747                 cfa_offset += sizeof (gpointer);
4748                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4749                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
4750                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
4751                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
4752         }
4753
4754         alloc_size = cfg->stack_offset;
4755         pos = 0;
4756
4757         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4758                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
4759                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
4760                         guint8 *buf, *no_domain_branch;
4761
4762                         code = mono_x86_emit_tls_get (code, X86_EAX, appdomain_tls_offset);
4763                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
4764                         no_domain_branch = code;
4765                         x86_branch8 (code, X86_CC_NE, 0, 0);
4766                         code = mono_x86_emit_tls_get ( code, X86_EAX, lmf_tls_offset);
4767                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
4768                         buf = code;
4769                         x86_branch8 (code, X86_CC_NE, 0, 0);
4770                         x86_patch (no_domain_branch, code);
4771                         x86_push_imm (code, cfg->domain);
4772                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4773                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4774                         x86_patch (buf, code);
4775 #ifdef TARGET_WIN32
4776                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4777                         /* FIXME: Add a separate key for LMF to avoid this */
4778                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4779 #endif
4780                 }
4781                 else {
4782                         if (cfg->compile_aot) {
4783                                 /* 
4784                                  * This goes before the saving of callee saved regs, so save the got reg
4785                                  * ourselves.
4786                                  */
4787                                 x86_push_reg (code, MONO_ARCH_GOT_REG);
4788                                 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
4789                                 x86_push_imm (code, 0);
4790                         } else {
4791                                 x86_push_imm (code, cfg->domain);
4792                         }
4793                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4794                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
4795                         if (cfg->compile_aot)
4796                                 x86_pop_reg (code, MONO_ARCH_GOT_REG);
4797                 }
4798         }
4799
4800         if (method->save_lmf) {
4801                 pos += sizeof (MonoLMF);
4802
4803                 /* save the current IP */
4804                 if (cfg->compile_aot) {
4805                         /* This pushes the current ip */
4806                         x86_call_imm (code, 0);
4807                 } else {
4808                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4809                         x86_push_imm_template (code);
4810                 }
4811                 cfa_offset += sizeof (gpointer);
4812
4813                 /* save all caller saved regs */
4814                 x86_push_reg (code, X86_EBP);
4815                 cfa_offset += sizeof (gpointer);
4816                 x86_push_reg (code, X86_ESI);
4817                 cfa_offset += sizeof (gpointer);
4818                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4819                 x86_push_reg (code, X86_EDI);
4820                 cfa_offset += sizeof (gpointer);
4821                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4822                 x86_push_reg (code, X86_EBX);
4823                 cfa_offset += sizeof (gpointer);
4824                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4825
4826                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4827                         /*
4828                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4829                          * through the mono_lmf_addr TLS variable.
4830                          */
4831                         /* %eax = previous_lmf */
4832                         x86_prefix (code, X86_GS_PREFIX);
4833                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
4834                         /* skip esp + method_info + lmf */
4835                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
4836                         /* push previous_lmf */
4837                         x86_push_reg (code, X86_EAX);
4838                         /* new lmf = ESP */
4839                         x86_prefix (code, X86_GS_PREFIX);
4840                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
4841                 } else {
4842                         /* get the address of lmf for the current thread */
4843                         /* 
4844                          * This is performance critical so we try to use some tricks to make
4845                          * it fast.
4846                          */                                                                        
4847
4848                         if (lmf_addr_tls_offset != -1) {
4849                                 /* Load lmf quicky using the GS register */
4850                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
4851 #ifdef TARGET_WIN32
4852                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4853                                 /* FIXME: Add a separate key for LMF to avoid this */
4854                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4855 #endif
4856                         } else {
4857                                 if (cfg->compile_aot)
4858                                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
4859                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
4860                         }
4861
4862                         /* Skip esp + method info */
4863                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
4864
4865                         /* push lmf */
4866                         x86_push_reg (code, X86_EAX); 
4867                         /* push *lfm (previous_lmf) */
4868                         x86_push_membase (code, X86_EAX, 0);
4869                         /* *(lmf) = ESP */
4870                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
4871                 }
4872         } else {
4873
4874                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4875                         x86_push_reg (code, X86_EBX);
4876                         pos += 4;
4877                         cfa_offset += sizeof (gpointer);
4878                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
4879                 }
4880
4881                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4882                         x86_push_reg (code, X86_EDI);
4883                         pos += 4;
4884                         cfa_offset += sizeof (gpointer);
4885                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
4886                 }
4887
4888                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4889                         x86_push_reg (code, X86_ESI);
4890                         pos += 4;
4891                         cfa_offset += sizeof (gpointer);
4892                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
4893                 }
4894         }
4895
4896         alloc_size -= pos;
4897
4898         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
4899         if (mono_do_x86_stack_align && need_stack_frame) {
4900                 int tot = alloc_size + pos + 4; /* ret ip */
4901                 if (need_stack_frame)
4902                         tot += 4; /* ebp */
4903                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
4904                 if (tot)
4905                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
4906         }
4907
4908         if (alloc_size) {
4909                 /* See mono_emit_stack_alloc */
4910 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4911                 guint32 remaining_size = alloc_size;
4912                 /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
4913                 guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 8; /*8 is the max size of x86_alu_reg_imm + x86_test_membase_reg*/
4914                 guint32 offset = code - cfg->native_code;
4915                 if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
4916                         while (required_code_size >= (cfg->code_size - offset))
4917                                 cfg->code_size *= 2;
4918                         cfg->native_code = mono_realloc_native_code(cfg);
4919                         code = cfg->native_code + offset;
4920                         mono_jit_stats.code_reallocs++;
4921                 }
4922                 while (remaining_size >= 0x1000) {
4923                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
4924                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
4925                         remaining_size -= 0x1000;
4926                 }
4927                 if (remaining_size)
4928                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
4929 #else
4930                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4931 #endif
4932
4933                 g_assert (need_stack_frame);
4934         }
4935
4936         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
4937                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
4938                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
4939         }
4940
4941 #if DEBUG_STACK_ALIGNMENT
4942         /* check the stack is aligned */
4943         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
4944                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
4945                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
4946                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4947                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4948                 x86_breakpoint (code);
4949         }
4950 #endif
4951
4952         /* compute max_offset in order to use short forward jumps */
4953         max_offset = 0;
4954         if (cfg->opt & MONO_OPT_BRANCH) {
4955                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4956                         MonoInst *ins;
4957                         bb->max_offset = max_offset;
4958
4959                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4960                                 max_offset += 6;
4961                         /* max alignment for loops */
4962                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4963                                 max_offset += LOOP_ALIGNMENT;
4964 #ifdef __native_client_codegen__
4965                         /* max alignment for native client */
4966                         max_offset += kNaClAlignment;
4967 #endif
4968                         MONO_BB_FOR_EACH_INS (bb, ins) {
4969                                 if (ins->opcode == OP_LABEL)
4970                                         ins->inst_c1 = max_offset;
4971 #ifdef __native_client_codegen__
4972                                 {
4973                                         int space_in_block = kNaClAlignment -
4974                                                 ((max_offset + cfg->code_len) & kNaClAlignmentMask);
4975                                         int max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4976                                         if (space_in_block < max_len && max_len < kNaClAlignment) {
4977                                                 max_offset += space_in_block;
4978                                         }
4979                                 }
4980 #endif  /* __native_client_codegen__ */
4981                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4982                         }
4983                 }
4984         }
4985
4986         /* store runtime generic context */
4987         if (cfg->rgctx_var) {
4988                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4989
4990                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4991         }
4992
4993         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4994                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4995
4996         /* load arguments allocated to register from the stack */
4997         sig = mono_method_signature (method);
4998         pos = 0;
4999
5000         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5001                 inst = cfg->args [pos];
5002                 if (inst->opcode == OP_REGVAR) {
5003                         g_assert (need_stack_frame);
5004                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
5005                         if (cfg->verbose_level > 2)
5006                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5007                 }
5008                 pos++;
5009         }
5010
5011         cfg->code_len = code - cfg->native_code;
5012
5013         g_assert (cfg->code_len < cfg->code_size);
5014
5015         return code;
5016 }
5017
5018 void
5019 mono_arch_emit_epilog (MonoCompile *cfg)
5020 {
5021         MonoMethod *method = cfg->method;
5022         MonoMethodSignature *sig = mono_method_signature (method);
5023         int quad, pos;
5024         guint32 stack_to_pop;
5025         guint8 *code;
5026         int max_epilog_size = 16;
5027         CallInfo *cinfo;
5028         gboolean need_stack_frame = needs_stack_frame (cfg);
5029
5030         if (cfg->method->save_lmf)
5031                 max_epilog_size += 128;
5032
5033         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5034                 cfg->code_size *= 2;
5035                 cfg->native_code = mono_realloc_native_code(cfg);
5036                 mono_jit_stats.code_reallocs++;
5037         }
5038
5039         code = cfg->native_code + cfg->code_len;
5040
5041         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5042                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5043
5044         /* the code restoring the registers must be kept in sync with OP_JMP */
5045         pos = 0;
5046         
5047         if (method->save_lmf) {
5048                 gint32 prev_lmf_reg;
5049                 gint32 lmf_offset = -sizeof (MonoLMF);
5050
5051                 /* check if we need to restore protection of the stack after a stack overflow */
5052                 if (mono_get_jit_tls_offset () != -1) {
5053                         guint8 *patch;
5054                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
5055                         /* we load the value in a separate instruction: this mechanism may be
5056                          * used later as a safer way to do thread interruption
5057                          */
5058                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
5059                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5060                         patch = code;
5061                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
5062                         /* note that the call trampoline will preserve eax/edx */
5063                         x86_call_reg (code, X86_ECX);
5064                         x86_patch (patch, code);
5065                 } else {
5066                         /* FIXME: maybe save the jit tls in the prolog */
5067                 }
5068                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5069                         /*
5070                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5071                          * through the mono_lmf_addr TLS variable.
5072                          */
5073                         /* reg = previous_lmf */
5074                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5075
5076                         /* lmf = previous_lmf */
5077                         x86_prefix (code, X86_GS_PREFIX);
5078                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
5079                 } else {
5080                         /* Find a spare register */
5081                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
5082                         case MONO_TYPE_I8:
5083                         case MONO_TYPE_U8:
5084                                 prev_lmf_reg = X86_EDI;
5085                                 cfg->used_int_regs |= (1 << X86_EDI);
5086                                 break;
5087                         default:
5088                                 prev_lmf_reg = X86_EDX;
5089                                 break;
5090                         }
5091
5092                         /* reg = previous_lmf */
5093                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5094
5095                         /* ecx = lmf */
5096                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
5097
5098                         /* *(lmf) = previous_lmf */
5099                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
5100                 }
5101
5102                 /* restore caller saved regs */
5103                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5104                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
5105                 }
5106
5107                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5108                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
5109                 }
5110                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5111                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
5112                 }
5113
5114                 /* EBP is restored by LEAVE */
5115         } else {
5116                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5117                         pos -= 4;
5118                 }
5119                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5120                         pos -= 4;
5121                 }
5122                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5123                         pos -= 4;
5124                 }
5125
5126                 if (pos) {
5127                         g_assert (need_stack_frame);
5128                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
5129                 }
5130
5131                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5132                         x86_pop_reg (code, X86_ESI);
5133                 }
5134                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5135                         x86_pop_reg (code, X86_EDI);
5136                 }
5137                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5138                         x86_pop_reg (code, X86_EBX);
5139                 }
5140         }
5141
5142         /* Load returned vtypes into registers if needed */
5143         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
5144         if (cinfo->ret.storage == ArgValuetypeInReg) {
5145                 for (quad = 0; quad < 2; quad ++) {
5146                         switch (cinfo->ret.pair_storage [quad]) {
5147                         case ArgInIReg:
5148                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
5149                                 break;
5150                         case ArgOnFloatFpStack:
5151                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
5152                                 break;
5153                         case ArgOnDoubleFpStack:
5154                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
5155                                 break;
5156                         case ArgNone:
5157                                 break;
5158                         default:
5159                                 g_assert_not_reached ();
5160                         }
5161                 }
5162         }
5163
5164         if (need_stack_frame)
5165                 x86_leave (code);
5166
5167         if (CALLCONV_IS_STDCALL (sig)) {
5168                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
5169
5170                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
5171         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
5172                 stack_to_pop = 4;
5173         else
5174                 stack_to_pop = 0;
5175
5176         if (stack_to_pop) {
5177                 g_assert (need_stack_frame);
5178                 x86_ret_imm (code, stack_to_pop);
5179         } else {
5180                 x86_ret (code);
5181         }
5182
5183         cfg->code_len = code - cfg->native_code;
5184
5185         g_assert (cfg->code_len < cfg->code_size);
5186 }
5187
5188 void
5189 mono_arch_emit_exceptions (MonoCompile *cfg)
5190 {
5191         MonoJumpInfo *patch_info;
5192         int nthrows, i;
5193         guint8 *code;
5194         MonoClass *exc_classes [16];
5195         guint8 *exc_throw_start [16], *exc_throw_end [16];
5196         guint32 code_size;
5197         int exc_count = 0;
5198
5199         /* Compute needed space */
5200         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5201                 if (patch_info->type == MONO_PATCH_INFO_EXC)
5202                         exc_count++;
5203         }
5204
5205         /* 
5206          * make sure we have enough space for exceptions
5207          * 16 is the size of two push_imm instructions and a call
5208          */
5209         if (cfg->compile_aot)
5210                 code_size = exc_count * 32;
5211         else
5212                 code_size = exc_count * 16;
5213
5214         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
5215                 cfg->code_size *= 2;
5216                 cfg->native_code = mono_realloc_native_code(cfg);
5217                 mono_jit_stats.code_reallocs++;
5218         }
5219
5220         code = cfg->native_code + cfg->code_len;
5221
5222         nthrows = 0;
5223         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5224                 switch (patch_info->type) {
5225                 case MONO_PATCH_INFO_EXC: {
5226                         MonoClass *exc_class;
5227                         guint8 *buf, *buf2;
5228                         guint32 throw_ip;
5229
5230                         x86_patch (patch_info->ip.i + cfg->native_code, code);
5231
5232                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5233                         g_assert (exc_class);
5234                         throw_ip = patch_info->ip.i;
5235
5236                         /* Find a throw sequence for the same exception class */
5237                         for (i = 0; i < nthrows; ++i)
5238                                 if (exc_classes [i] == exc_class)
5239                                         break;
5240                         if (i < nthrows) {
5241                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
5242                                 x86_jump_code (code, exc_throw_start [i]);
5243                                 patch_info->type = MONO_PATCH_INFO_NONE;
5244                         }
5245                         else {
5246                                 guint32 size;
5247
5248                                 /* Compute size of code following the push <OFFSET> */
5249 #ifdef __native_client_codegen__
5250                                 code = mono_nacl_align (code);
5251                                 size = kNaClAlignment;
5252 #else
5253                                 size = 5 + 5;
5254 #endif
5255                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
5256
5257                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
5258                                         /* Use the shorter form */
5259                                         buf = buf2 = code;
5260                                         x86_push_imm (code, 0);
5261                                 }
5262                                 else {
5263                                         buf = code;
5264                                         x86_push_imm (code, 0xf0f0f0f0);
5265                                         buf2 = code;
5266                                 }
5267
5268                                 if (nthrows < 16) {
5269                                         exc_classes [nthrows] = exc_class;
5270                                         exc_throw_start [nthrows] = code;
5271                                 }
5272
5273                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
5274                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
5275                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5276                                 patch_info->ip.i = code - cfg->native_code;
5277                                 x86_call_code (code, 0);
5278                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
5279                                 while (buf < buf2)
5280                                         x86_nop (buf);
5281
5282                                 if (nthrows < 16) {
5283                                         exc_throw_end [nthrows] = code;
5284                                         nthrows ++;
5285                                 }
5286                         }
5287                         break;
5288                 }
5289                 default:
5290                         /* do nothing */
5291                         break;
5292                 }
5293         }
5294
5295         cfg->code_len = code - cfg->native_code;
5296
5297         g_assert (cfg->code_len < cfg->code_size);
5298 }
5299
5300 void
5301 mono_arch_flush_icache (guint8 *code, gint size)
5302 {
5303         /* not needed */
5304 }
5305
5306 void
5307 mono_arch_flush_register_windows (void)
5308 {
5309 }
5310
5311 gboolean 
5312 mono_arch_is_inst_imm (gint64 imm)
5313 {
5314         return TRUE;
5315 }
5316
5317 /*
5318  * Support for fast access to the thread-local lmf structure using the GS
5319  * segment register on NPTL + kernel 2.6.x.
5320  */
5321
5322 static gboolean tls_offset_inited = FALSE;
5323
5324 void
5325 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5326 {
5327         if (!tls_offset_inited) {
5328                 if (!getenv ("MONO_NO_TLS")) {
5329 #ifdef TARGET_WIN32
5330                         /* 
5331                          * We need to init this multiple times, since when we are first called, the key might not
5332                          * be initialized yet.
5333                          */
5334                         appdomain_tls_offset = mono_domain_get_tls_key ();
5335                         lmf_tls_offset = mono_get_jit_tls_key ();
5336
5337                         /* Only 64 tls entries can be accessed using inline code */
5338                         if (appdomain_tls_offset >= 64)
5339                                 appdomain_tls_offset = -1;
5340                         if (lmf_tls_offset >= 64)
5341                                 lmf_tls_offset = -1;
5342 #else
5343 #if MONO_XEN_OPT
5344                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5345 #endif
5346                         tls_offset_inited = TRUE;
5347                         appdomain_tls_offset = mono_domain_get_tls_offset ();
5348                         lmf_tls_offset = mono_get_lmf_tls_offset ();
5349                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5350 #endif
5351                 }
5352         }               
5353 }
5354
5355 void
5356 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5357 {
5358 }
5359
5360 #ifdef MONO_ARCH_HAVE_IMT
5361
5362 // Linear handler, the bsearch head compare is shorter
5363 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5364 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5365 //        x86_patch(ins,target)
5366 //[1 + 5] x86_jump_mem(inst,mem)
5367
5368 #define CMP_SIZE 6
5369 #ifdef __native_client_codegen__
5370 /* These constants should be coming from cpu-x86.md            */
5371 /* I suspect the size calculation below is actually incorrect. */
5372 /* TODO: fix the calculation that uses these sizes.            */
5373 #define BR_SMALL_SIZE 16
5374 #define BR_LARGE_SIZE 12
5375 #else
5376 #define BR_SMALL_SIZE 2
5377 #define BR_LARGE_SIZE 5
5378 #endif  /* __native_client_codegen__ */
5379 #define JUMP_IMM_SIZE 6
5380 #define ENABLE_WRONG_METHOD_CHECK 0
5381 #define DEBUG_IMT 0
5382
5383 static int
5384 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5385 {
5386         int i, distance = 0;
5387         for (i = start; i < target; ++i)
5388                 distance += imt_entries [i]->chunk_size;
5389         return distance;
5390 }
5391
5392 /*
5393  * LOCKING: called with the domain lock held
5394  */
5395 gpointer
5396 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5397         gpointer fail_tramp)
5398 {
5399         int i;
5400         int size = 0;
5401         guint8 *code, *start;
5402
5403 #ifdef __native_client_codegen__
5404         /* g_print("mono_arch_build_imt_thunk needs to be aligned.\n"); */
5405 #endif
5406         for (i = 0; i < count; ++i) {
5407                 MonoIMTCheckItem *item = imt_entries [i];
5408                 if (item->is_equals) {
5409                         if (item->check_target_idx) {
5410                                 if (!item->compare_done)
5411                                         item->chunk_size += CMP_SIZE;
5412                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5413                         } else {
5414                                 if (fail_tramp) {
5415                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5416                                 } else {
5417                                         item->chunk_size += JUMP_IMM_SIZE;
5418 #if ENABLE_WRONG_METHOD_CHECK
5419                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5420 #endif
5421                                 }
5422                         }
5423                 } else {
5424                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5425                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5426                 }
5427                 size += item->chunk_size;
5428         }
5429         if (fail_tramp)
5430                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5431         else
5432                 code = mono_domain_code_reserve (domain, size);
5433         start = code;
5434         for (i = 0; i < count; ++i) {
5435                 MonoIMTCheckItem *item = imt_entries [i];
5436                 item->code_target = code;
5437                 if (item->is_equals) {
5438                         if (item->check_target_idx) {
5439                                 if (!item->compare_done)
5440                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5441                                 item->jmp_code = code;
5442                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5443                                 if (item->has_target_code)
5444                                         x86_jump_code (code, item->value.target_code);
5445                                 else
5446                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5447                         } else {
5448                                 if (fail_tramp) {
5449                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5450                                         item->jmp_code = code;
5451                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5452                                         if (item->has_target_code)
5453                                                 x86_jump_code (code, item->value.target_code);
5454                                         else
5455                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5456                                         x86_patch (item->jmp_code, code);
5457                                         x86_jump_code (code, fail_tramp);
5458                                         item->jmp_code = NULL;
5459                                 } else {
5460                                         /* enable the commented code to assert on wrong method */
5461 #if ENABLE_WRONG_METHOD_CHECK
5462                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5463                                         item->jmp_code = code;
5464                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5465 #endif
5466                                         if (item->has_target_code)
5467                                                 x86_jump_code (code, item->value.target_code);
5468                                         else
5469                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5470 #if ENABLE_WRONG_METHOD_CHECK
5471                                         x86_patch (item->jmp_code, code);
5472                                         x86_breakpoint (code);
5473                                         item->jmp_code = NULL;
5474 #endif
5475                                 }
5476                         }
5477                 } else {
5478                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5479                         item->jmp_code = code;
5480                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5481                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5482                         else
5483                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5484                 }
5485         }
5486         /* patch the branches to get to the target items */
5487         for (i = 0; i < count; ++i) {
5488                 MonoIMTCheckItem *item = imt_entries [i];
5489                 if (item->jmp_code) {
5490                         if (item->check_target_idx) {
5491                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5492                         }
5493                 }
5494         }
5495
5496         if (!fail_tramp)
5497                 mono_stats.imt_thunks_size += code - start;
5498         g_assert (code - start <= size);
5499
5500 #if DEBUG_IMT
5501         {
5502                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5503                 mono_disassemble_code (NULL, (guint8*)start, code - start, buff);
5504                 g_free (buff);
5505         }
5506 #endif
5507
5508         return start;
5509 }
5510
5511 MonoMethod*
5512 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5513 {
5514         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5515 }
5516 #endif
5517
5518 MonoVTable*
5519 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5520 {
5521         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5522 }
5523
5524 GSList*
5525 mono_arch_get_cie_program (void)
5526 {
5527         GSList *l = NULL;
5528
5529         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
5530         mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
5531
5532         return l;
5533 }
5534
5535 MonoInst*
5536 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5537 {
5538         MonoInst *ins = NULL;
5539         int opcode = 0;
5540
5541         if (cmethod->klass == mono_defaults.math_class) {
5542                 if (strcmp (cmethod->name, "Sin") == 0) {
5543                         opcode = OP_SIN;
5544                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5545                         opcode = OP_COS;
5546                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5547                         opcode = OP_TAN;
5548                 } else if (strcmp (cmethod->name, "Atan") == 0) {
5549                         opcode = OP_ATAN;
5550                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5551                         opcode = OP_SQRT;
5552                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5553                         opcode = OP_ABS;
5554                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
5555                         opcode = OP_ROUND;
5556                 }
5557                 
5558                 if (opcode) {
5559                         MONO_INST_NEW (cfg, ins, opcode);
5560                         ins->type = STACK_R8;
5561                         ins->dreg = mono_alloc_freg (cfg);
5562                         ins->sreg1 = args [0]->dreg;
5563                         MONO_ADD_INS (cfg->cbb, ins);
5564                 }
5565
5566                 if (cfg->opt & MONO_OPT_CMOV) {
5567                         int opcode = 0;
5568
5569                         if (strcmp (cmethod->name, "Min") == 0) {
5570                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5571                                         opcode = OP_IMIN;
5572                         } else if (strcmp (cmethod->name, "Max") == 0) {
5573                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5574                                         opcode = OP_IMAX;
5575                         }               
5576
5577                         if (opcode) {
5578                                 MONO_INST_NEW (cfg, ins, opcode);
5579                                 ins->type = STACK_I4;
5580                                 ins->dreg = mono_alloc_ireg (cfg);
5581                                 ins->sreg1 = args [0]->dreg;
5582                                 ins->sreg2 = args [1]->dreg;
5583                                 MONO_ADD_INS (cfg->cbb, ins);
5584                         }
5585                 }
5586
5587 #if 0
5588                 /* OP_FREM is not IEEE compatible */
5589                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
5590                         MONO_INST_NEW (cfg, ins, OP_FREM);
5591                         ins->inst_i0 = args [0];
5592                         ins->inst_i1 = args [1];
5593                 }
5594 #endif
5595         }
5596
5597         return ins;
5598 }
5599
5600 gboolean
5601 mono_arch_print_tree (MonoInst *tree, int arity)
5602 {
5603         return 0;
5604 }
5605
5606 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5607 {
5608         MonoInst* ins;
5609
5610         return NULL;
5611
5612         if (appdomain_tls_offset == -1)
5613                 return NULL;
5614
5615         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5616         ins->inst_offset = appdomain_tls_offset;
5617         return ins;
5618 }
5619
5620 guint32
5621 mono_arch_get_patch_offset (guint8 *code)
5622 {
5623         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
5624                 return 2;
5625         else if ((code [0] == 0xba))
5626                 return 1;
5627         else if ((code [0] == 0x68))
5628                 /* push IMM */
5629                 return 1;
5630         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
5631                 /* push <OFFSET>(<REG>) */
5632                 return 2;
5633         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
5634                 /* call *<OFFSET>(<REG>) */
5635                 return 2;
5636         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
5637                 /* fldl <ADDR> */
5638                 return 2;
5639         else if ((code [0] == 0x58) && (code [1] == 0x05))
5640                 /* pop %eax; add <OFFSET>, %eax */
5641                 return 2;
5642         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
5643                 /* pop <REG>; add <OFFSET>, <REG> */
5644                 return 3;
5645         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
5646                 /* mov <REG>, imm */
5647                 return 1;
5648         else {
5649                 g_assert_not_reached ();
5650                 return -1;
5651         }
5652 }
5653
5654 /**
5655  * mono_breakpoint_clean_code:
5656  *
5657  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
5658  * breakpoints in the original code, they are removed in the copy.
5659  *
5660  * Returns TRUE if no sw breakpoint was present.
5661  */
5662 gboolean
5663 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
5664 {
5665         int i;
5666         gboolean can_write = TRUE;
5667         /*
5668          * If method_start is non-NULL we need to perform bound checks, since we access memory
5669          * at code - offset we could go before the start of the method and end up in a different
5670          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
5671          * instead.
5672          */
5673         if (!method_start || code - offset >= method_start) {
5674                 memcpy (buf, code - offset, size);
5675         } else {
5676                 int diff = code - method_start;
5677                 memset (buf, 0, size);
5678                 memcpy (buf + offset - diff, method_start, diff + size - offset);
5679         }
5680         code -= offset;
5681         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
5682                 int idx = mono_breakpoint_info_index [i];
5683                 guint8 *ptr;
5684                 if (idx < 1)
5685                         continue;
5686                 ptr = mono_breakpoint_info [idx].address;
5687                 if (ptr >= code && ptr < code + size) {
5688                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
5689                         can_write = FALSE;
5690                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
5691                         buf [ptr - code] = saved_byte;
5692                 }
5693         }
5694         return can_write;
5695 }
5696
5697 /*
5698  * mono_x86_get_this_arg_offset:
5699  *
5700  *   Return the offset of the stack location where this is passed during a virtual
5701  * call.
5702  */
5703 guint32
5704 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
5705 {
5706         return 0;
5707 }
5708
5709 gpointer
5710 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
5711                 mgreg_t *regs, guint8 *code)
5712 {
5713         guint32 esp = regs [X86_ESP];
5714         CallInfo *cinfo = NULL;
5715         gpointer res;
5716         int offset;
5717
5718         offset = 0;
5719
5720         /*
5721          * The stack looks like:
5722          * <other args>
5723          * <this=delegate>
5724          * <return addr>
5725          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
5726          */
5727         res = (((MonoObject**)esp) [5 + (offset / 4)]);
5728         if (cinfo)
5729                 g_free (cinfo);
5730         return res;
5731 }
5732
5733 #define MAX_ARCH_DELEGATE_PARAMS 10
5734
5735 static gpointer
5736 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
5737 {
5738         guint8 *code, *start;
5739
5740         /*
5741          * The stack contains:
5742          * <delegate>
5743          * <return addr>
5744          */
5745
5746         if (has_target) {
5747                 start = code = mono_global_codeman_reserve (64);
5748
5749                 /* Replace the this argument with the target */
5750                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
5751                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
5752                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
5753                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5754
5755                 g_assert ((code - start) < 64);
5756         } else {
5757                 int i = 0;
5758                 /* 8 for mov_reg and jump, plus 8 for each parameter */
5759 #ifdef __native_client_codegen__
5760                 /* TODO: calculate this size correctly */
5761                 int code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment;
5762 #else
5763                 int code_reserve = 8 + (param_count * 8);
5764 #endif  /* __native_client_codegen__ */
5765                 /*
5766                  * The stack contains:
5767                  * <args in reverse order>
5768                  * <delegate>
5769                  * <return addr>
5770                  *
5771                  * and we need:
5772                  * <args in reverse order>
5773                  * <return addr>
5774                  * 
5775                  * without unbalancing the stack.
5776                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
5777                  * and leaving original spot of first arg as placeholder in stack so
5778                  * when callee pops stack everything works.
5779                  */
5780
5781                 start = code = mono_global_codeman_reserve (code_reserve);
5782
5783                 /* store delegate for access to method_ptr */
5784                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
5785
5786                 /* move args up */
5787                 for (i = 0; i < param_count; ++i) {
5788                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
5789                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
5790                 }
5791
5792                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5793
5794                 g_assert ((code - start) < code_reserve);
5795         }
5796
5797         mono_debug_add_delegate_trampoline (start, code - start);
5798
5799         if (code_len)
5800                 *code_len = code - start;
5801
5802         return start;
5803 }
5804
5805 GSList*
5806 mono_arch_get_delegate_invoke_impls (void)
5807 {
5808         GSList *res = NULL;
5809         guint8 *code;
5810         guint32 code_len;
5811         int i;
5812
5813         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
5814         res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
5815
5816         for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
5817                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
5818                 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
5819         }
5820
5821         return res;
5822 }
5823
5824 gpointer
5825 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5826 {
5827         guint8 *code, *start;
5828
5829         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
5830                 return NULL;
5831
5832         /* FIXME: Support more cases */
5833         if (MONO_TYPE_ISSTRUCT (sig->ret))
5834                 return NULL;
5835
5836         /*
5837          * The stack contains:
5838          * <delegate>
5839          * <return addr>
5840          */
5841
5842         if (has_target) {
5843                 static guint8* cached = NULL;
5844                 if (cached)
5845                         return cached;
5846
5847                 if (mono_aot_only)
5848                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
5849                 else
5850                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
5851
5852                 mono_memory_barrier ();
5853
5854                 cached = start;
5855         } else {
5856                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
5857                 int i = 0;
5858
5859                 for (i = 0; i < sig->param_count; ++i)
5860                         if (!mono_is_regsize_var (sig->params [i]))
5861                                 return NULL;
5862
5863                 code = cache [sig->param_count];
5864                 if (code)
5865                         return code;
5866
5867                 if (mono_aot_only) {
5868                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
5869                         start = mono_aot_get_trampoline (name);
5870                         g_free (name);
5871                 } else {
5872                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
5873                 }
5874
5875                 mono_memory_barrier ();
5876
5877                 cache [sig->param_count] = start;
5878         }
5879
5880         return start;
5881 }
5882
5883 gpointer
5884 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5885 {
5886         switch (reg) {
5887         case X86_EAX: return (gpointer)ctx->eax;
5888         case X86_EBX: return (gpointer)ctx->ebx;
5889         case X86_ECX: return (gpointer)ctx->ecx;
5890         case X86_EDX: return (gpointer)ctx->edx;
5891         case X86_ESP: return (gpointer)ctx->esp;
5892         case X86_EBP: return (gpointer)ctx->ebp;
5893         case X86_ESI: return (gpointer)ctx->esi;
5894         case X86_EDI: return (gpointer)ctx->edi;
5895         default: g_assert_not_reached ();
5896         }
5897 }
5898
5899 #ifdef MONO_ARCH_SIMD_INTRINSICS
5900
5901 static MonoInst*
5902 get_float_to_x_spill_area (MonoCompile *cfg)
5903 {
5904         if (!cfg->fconv_to_r8_x_var) {
5905                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5906                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
5907         }       
5908         return cfg->fconv_to_r8_x_var;
5909 }
5910
5911 /*
5912  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
5913  */
5914 void
5915 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5916 {
5917         MonoInst *fconv;
5918         int dreg, src_opcode;
5919
5920         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
5921                 return;
5922
5923         switch (src_opcode = ins->opcode) {
5924         case OP_FCONV_TO_I1:
5925         case OP_FCONV_TO_U1:
5926         case OP_FCONV_TO_I2:
5927         case OP_FCONV_TO_U2:
5928         case OP_FCONV_TO_I4:
5929         case OP_FCONV_TO_I:
5930                 break;
5931         default:
5932                 return;
5933         }
5934
5935         /* dreg is the IREG and sreg1 is the FREG */
5936         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
5937         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
5938         fconv->sreg1 = ins->sreg1;
5939         fconv->dreg = mono_alloc_ireg (cfg);
5940         fconv->type = STACK_VTYPE;
5941         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
5942
5943         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
5944
5945         dreg = ins->dreg;
5946         NULLIFY_INS (ins);
5947         ins->opcode = OP_XCONV_R8_TO_I4;
5948
5949         ins->klass = mono_defaults.int32_class;
5950         ins->sreg1 = fconv->dreg;
5951         ins->dreg = dreg;
5952         ins->type = STACK_I4;
5953         ins->backend.source_opcode = src_opcode;
5954 }
5955
5956 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
5957
5958 void
5959 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
5960 {
5961         MonoInst *ins;
5962         int vreg;
5963
5964         if (long_ins->opcode == OP_LNEG) {
5965                 ins = long_ins;
5966                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
5967                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
5968                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
5969                 NULLIFY_INS (ins);
5970                 return;
5971         }
5972
5973 #ifdef MONO_ARCH_SIMD_INTRINSICS
5974
5975         if (!(cfg->opt & MONO_OPT_SIMD))
5976                 return;
5977         
5978         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
5979         switch (long_ins->opcode) {
5980         case OP_EXTRACT_I8:
5981                 vreg = long_ins->sreg1;
5982         
5983                 if (long_ins->inst_c0) {
5984                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
5985                         ins->klass = long_ins->klass;
5986                         ins->sreg1 = long_ins->sreg1;
5987                         ins->inst_c0 = 2;
5988                         ins->type = STACK_VTYPE;
5989                         ins->dreg = vreg = alloc_ireg (cfg);
5990                         MONO_ADD_INS (cfg->cbb, ins);
5991                 }
5992         
5993                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
5994                 ins->klass = mono_defaults.int32_class;
5995                 ins->sreg1 = vreg;
5996                 ins->type = STACK_I4;
5997                 ins->dreg = long_ins->dreg + 1;
5998                 MONO_ADD_INS (cfg->cbb, ins);
5999         
6000                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6001                 ins->klass = long_ins->klass;
6002                 ins->sreg1 = long_ins->sreg1;
6003                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
6004                 ins->type = STACK_VTYPE;
6005                 ins->dreg = vreg = alloc_ireg (cfg);
6006                 MONO_ADD_INS (cfg->cbb, ins);
6007         
6008                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6009                 ins->klass = mono_defaults.int32_class;
6010                 ins->sreg1 = vreg;
6011                 ins->type = STACK_I4;
6012                 ins->dreg = long_ins->dreg + 2;
6013                 MONO_ADD_INS (cfg->cbb, ins);
6014         
6015                 long_ins->opcode = OP_NOP;
6016                 break;
6017         case OP_INSERTX_I8_SLOW:
6018                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6019                 ins->dreg = long_ins->dreg;
6020                 ins->sreg1 = long_ins->dreg;
6021                 ins->sreg2 = long_ins->sreg2 + 1;
6022                 ins->inst_c0 = long_ins->inst_c0 * 2;
6023                 MONO_ADD_INS (cfg->cbb, ins);
6024
6025                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6026                 ins->dreg = long_ins->dreg;
6027                 ins->sreg1 = long_ins->dreg;
6028                 ins->sreg2 = long_ins->sreg2 + 2;
6029                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
6030                 MONO_ADD_INS (cfg->cbb, ins);
6031
6032                 long_ins->opcode = OP_NOP;
6033                 break;
6034         case OP_EXPAND_I8:
6035                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
6036                 ins->dreg = long_ins->dreg;
6037                 ins->sreg1 = long_ins->sreg1 + 1;
6038                 ins->klass = long_ins->klass;
6039                 ins->type = STACK_VTYPE;
6040                 MONO_ADD_INS (cfg->cbb, ins);
6041
6042                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6043                 ins->dreg = long_ins->dreg;
6044                 ins->sreg1 = long_ins->dreg;
6045                 ins->sreg2 = long_ins->sreg1 + 2;
6046                 ins->inst_c0 = 1;
6047                 ins->klass = long_ins->klass;
6048                 ins->type = STACK_VTYPE;
6049                 MONO_ADD_INS (cfg->cbb, ins);
6050
6051                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6052                 ins->dreg = long_ins->dreg;
6053                 ins->sreg1 = long_ins->dreg;;
6054                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
6055                 ins->klass = long_ins->klass;
6056                 ins->type = STACK_VTYPE;
6057                 MONO_ADD_INS (cfg->cbb, ins);
6058
6059                 long_ins->opcode = OP_NOP;
6060                 break;
6061         }
6062 #endif /* MONO_ARCH_SIMD_INTRINSICS */
6063 }
6064
6065 /*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
6066 gpointer
6067 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
6068 {
6069         int offset;
6070         gpointer *sp, old_value;
6071         char *bp;
6072         const unsigned char *handler;
6073
6074         /*Decode the first instruction to figure out where did we store the spvar*/
6075         /*Our jit MUST generate the following:
6076          mov %esp, -?(%ebp)
6077          Which is encoded as: 0x89 mod_rm.
6078          mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
6079                 mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
6080                 mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
6081         */
6082         handler = clause->handler_start;
6083
6084         if (*handler != 0x89)
6085                 return NULL;
6086
6087         ++handler;
6088
6089         if (*handler == 0x65)
6090                 offset = *(signed char*)(handler + 1);
6091         else if (*handler == 0xA5)
6092                 offset = *(int*)(handler + 1);
6093         else
6094                 return NULL;
6095
6096         /*Load the spvar*/
6097         bp = MONO_CONTEXT_GET_BP (ctx);
6098         sp = *(gpointer*)(bp + offset);
6099
6100         old_value = *sp;
6101         if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
6102                 return old_value;
6103
6104         *sp = new_value;
6105
6106         return old_value;
6107 }
6108
6109 /*
6110  * mono_aot_emit_load_got_addr:
6111  *
6112  *   Emit code to load the got address.
6113  * On x86, the result is placed into EBX.
6114  */
6115 guint8*
6116 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6117 {
6118         x86_call_imm (code, 0);
6119         /* 
6120          * The patch needs to point to the pop, since the GOT offset needs 
6121          * to be added to that address.
6122          */
6123         if (cfg)
6124                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6125         else
6126                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6127         x86_pop_reg (code, MONO_ARCH_GOT_REG);
6128         x86_alu_reg_imm (code, X86_ADD, MONO_ARCH_GOT_REG, 0xf0f0f0f0);
6129
6130         return code;
6131 }
6132
6133 /*
6134  * mono_ppc_emit_load_aotconst:
6135  *
6136  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6137  * TARGET from the mscorlib GOT in full-aot code.
6138  * On x86, the GOT address is assumed to be in EBX, and the result is placed into 
6139  * EAX.
6140  */
6141 guint8*
6142 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6143 {
6144         /* Load the mscorlib got address */
6145         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
6146         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6147         /* arch_emit_got_access () patches this */
6148         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0xf0f0f0f0, 4);
6149
6150         return code;
6151 }
6152
6153 /* Can't put this into mini-x86.h */
6154 gpointer
6155 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot);
6156
6157 GSList *
6158 mono_arch_get_trampolines (gboolean aot)
6159 {
6160         MonoTrampInfo *info;
6161         GSList *tramps = NULL;
6162
6163         mono_x86_get_signal_exception_trampoline (&info, aot);
6164
6165         tramps = g_slist_append (tramps, info);
6166
6167         return tramps;
6168 }
6169
6170
6171 #if __APPLE__
6172 #define DBG_SIGNAL SIGBUS
6173 #else
6174 #define DBG_SIGNAL SIGSEGV
6175 #endif
6176
6177 /* Soft Debug support */
6178 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6179
6180 /*
6181  * mono_arch_set_breakpoint:
6182  *
6183  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
6184  * The location should contain code emitted by OP_SEQ_POINT.
6185  */
6186 void
6187 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6188 {
6189         guint8 *code = ip;
6190
6191         /* 
6192          * In production, we will use int3 (has to fix the size in the md 
6193          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
6194          * instead.
6195          */
6196         g_assert (code [0] == 0x90);
6197         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
6198 }
6199
6200 /*
6201  * mono_arch_clear_breakpoint:
6202  *
6203  *   Clear the breakpoint at IP.
6204  */
6205 void
6206 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6207 {
6208         guint8 *code = ip;
6209         int i;
6210
6211         for (i = 0; i < 6; ++i)
6212                 x86_nop (code);
6213 }
6214         
6215 /*
6216  * mono_arch_start_single_stepping:
6217  *
6218  *   Start single stepping.
6219  */
6220 void
6221 mono_arch_start_single_stepping (void)
6222 {
6223         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6224 }
6225         
6226 /*
6227  * mono_arch_stop_single_stepping:
6228  *
6229  *   Stop single stepping.
6230  */
6231 void
6232 mono_arch_stop_single_stepping (void)
6233 {
6234         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6235 }
6236
6237 /*
6238  * mono_arch_is_single_step_event:
6239  *
6240  *   Return whenever the machine state in SIGCTX corresponds to a single
6241  * step event.
6242  */
6243 gboolean
6244 mono_arch_is_single_step_event (void *info, void *sigctx)
6245 {
6246 #ifdef TARGET_WIN32
6247         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
6248         if ((einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
6249                 return TRUE;
6250         else
6251                 return FALSE;
6252 #else
6253         siginfo_t* sinfo = (siginfo_t*) info;
6254         /* Sometimes the address is off by 4 */
6255         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
6256                 return TRUE;
6257         else
6258                 return FALSE;
6259 #endif
6260 }
6261
6262 gboolean
6263 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6264 {
6265 #ifdef TARGET_WIN32
6266         EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
6267         if ((einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
6268                 return TRUE;
6269         else
6270                 return FALSE;
6271 #else
6272         siginfo_t* sinfo = (siginfo_t*)info;
6273         /* Sometimes the address is off by 4 */
6274         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
6275                 return TRUE;
6276         else
6277                 return FALSE;
6278 #endif
6279 }
6280
6281 /*
6282  * mono_arch_get_ip_for_breakpoint:
6283  *
6284  *   See mini-amd64.c for docs.
6285  */
6286 guint8*
6287 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6288 {
6289         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6290
6291         return ip;
6292 }
6293
6294 #define BREAKPOINT_SIZE 6
6295
6296 /*
6297  * mono_arch_get_ip_for_single_step:
6298  *
6299  *   See mini-amd64.c for docs.
6300  */
6301 guint8*
6302 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6303 {
6304         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6305
6306         /* Size of x86_alu_reg_imm */
6307         ip += 6;
6308
6309         return ip;
6310 }
6311
6312 /*
6313  * mono_arch_skip_breakpoint:
6314  *
6315  *   See mini-amd64.c for docs.
6316  */
6317 void
6318 mono_arch_skip_breakpoint (MonoContext *ctx)
6319 {
6320         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6321 }
6322
6323 /*
6324  * mono_arch_skip_single_step:
6325  *
6326  *   See mini-amd64.c for docs.
6327  */
6328 void
6329 mono_arch_skip_single_step (MonoContext *ctx)
6330 {
6331         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
6332 }
6333
6334 /*
6335  * mono_arch_get_seq_point_info:
6336  *
6337  *   See mini-amd64.c for docs.
6338  */
6339 gpointer
6340 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6341 {
6342         NOT_IMPLEMENTED;
6343         return NULL;
6344 }
6345
6346 #endif
6347