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