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