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