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