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