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