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