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