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