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