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