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